slew docs/runtimes/nextjs

Deploying Next.js

Next.js runs on slew as the real Node server it builds — SSR, API routes and middleware included. One config line, then git push; the builder does the rest.

Build standalone

// next.config.js
module.exports = {
  output: 'standalone',
}

next build then produces .next/standalone: a self-contained server with its own pruned node_modules. This is the official deployment output for self-hosting Next, and it's what slew detects.

Standalone doesn't remove features. It's a packaging mode, not a runtime mode — the file that runs is the same Next server as next start, with dependency tracing to keep the bundle small. SSR, App and Pages Router, route handlers, middleware, server actions, ISR and next/image (Next 15+ ships sharp) all work exactly as before. The two things standalone genuinely changes — it doesn't serve .next/static or public/ itself — are the two things the builder hands to the CDN for you.

Push to GitHub — detected automatically

Connect the repo and every push deploys. The builder recognizes a standalone build and assembles the artifact for you:

slew.json                { "server": "server/server.js" }
server/                  the standalone bundle (server.js, node_modules, .next server pieces)
static/_next/static/     .next/static — fingerprinted, served immutable by the CDN
static/                  public/ — served by the CDN

Leave the build settings at their defaults and connect:

slew git connect owner/repo

Two details the assembly handles that self-hosting guides usually make you do by hand: /_next/static/* is served straight from the CDN instead of by your server, and public/ is too. Monorepos work — the builder finds server.js where standalone output mirrors your repo layout.

Because the standalone bundle carries its own node_modules, Next ships via git push-to-deployslew deploy never packs node_modules.

How it runs

The standard server contract applies: the platform injects PORT (standalone binds 0.0.0.0, so no host config), env vars come from slew env — scope build-time variables with --scope build so next build sees them — and slew logs tails the live instance. Idle apps scale to zero; plans include apps kept ready that answer without a wake-up. Deploys are zero-downtime: the new version must pass a health check before traffic cuts over.

Every pull request gets its own preview URL that updates per push and expires after 7 days.

ISR and revalidation

ISR works the way Next emits it: pages with revalidate produce s-maxage + stale-while-revalidate headers, and the platform honors them — fresh copies answer from the cache without waking the instance, stale ones answer immediately while the refresh runs behind. For revalidatePath()-style eviction across every platform cache layer, POST to the project's revalidate endpoint — it takes a deploy token, so a CMS webhook can call it.

Limitations, stated plainly

  • No edge runtime: middleware runs in your Node server in the EU, not in a PoP fleet. Force it with runtime: 'nodejs' where you'd otherwise target edge.
  • next/image optimization runs in your server process by default. A one-line custom loader moves it to the platform's optimizer instead — resized WebP served from the CDN edge, without waking your instance.
  • One region: rendering happens in Germany; static assets and ISR pages are cached at the CDN edge.