Next.js path · Shipping it · Topic 10 of 11

Deployment targets: Node server, static export, platforms

Not started

A Next.js app can be deployed in four ways: as a Node.js server you run yourself, as a Docker container (the same server, packaged), as a static export with no server at all, or through a platform adapter such as Vercel's or Bun's. The first two support every feature. A static export supports only what can be computed at build time. Adapters support what their platform provides. Most surprises after deployment come from running several copies of the server, or from a serverless platform that throws away memory between requests.

Why it matters: The same code behaves differently on one Node server, ten containers, serverless functions or a folder of HTML. Caches, Server Actions and image optimisation all depend on what the target provides.

  1. 1Node.js server supports everything

    `next build` then `next start` (or a Docker image built with `output: "standalone"`) runs every feature: streaming, caching, actions, Proxy, image optimisation.

  2. 2Static export drops the server

    `output: "export"` writes HTML, CSS and JS to `out/`. Anything that needs a request at runtime (cookies, Proxy, Server Actions, ISR, default image optimisation) is unavailable.

  3. 3Many instances need shared state

    Each instance has its own in-memory cache and, by default, its own Server Action encryption key per build. Share the cache through a handler, fix the key, and set a `deploymentId` against version skew.

  4. 4Node.js, not Edge

    The Edge runtime is deprecated for routes; remove `export const runtime = "edge"`. Proxy and Cache Components run on Node.js.

1

How it works

The explanation, with examples you can run.

A Node.js server

{ "scripts": { "build": "next build", "start": "next start" } }

next start serves prerendered shells, streams dynamic holes, runs Server Actions, Route Handlers and Proxy, and optimises images. For containers, output: "standalone" copies only the files and node_modules the server needs into .next/standalone, which keeps images small. Put a reverse proxy such as nginx in front: it deals with slow clients and malformed requests better than the app server.

A static export

// next.config.tsexport default { output: "export" }

next build then writes out/ with one HTML file per route, which any static host or bucket can serve. Not available: dynamic routes without generateStaticParams, cookies and headers, rewrites, redirects, Proxy, Server Actions, ISR, draft mode, and image optimisation with the default loader (use a custom loader or unoptimized). It is a good start for a marketing site or an SPA, and you can switch to a server later.

Many instances

When you scale out, each copy of the server starts with its own state:

  • Cache: the default use cache store is in memory per instance, and the ISR page cache is on local disk. Configure cacheHandlers (for use cache: remote) or cacheHandler with Redis or similar so all instances share entries and tag invalidations.
  • Server Action keys: closure encryption uses a key generated per build. Build once and deploy the same artifact everywhere, or set NEXT_SERVER_ACTIONS_ENCRYPTION_KEY.
  • Version skew: during a rolling deploy, a browser may hold an old page and talk to a new server. Setting deploymentId lets Next.js detect the mismatch and do a full reload instead of a broken client navigation.

Runtimes

Next.js has two server runtimes. Node.js is the default and supports everything. The Edge runtime, a subset of Web APIs that once promised faster cold starts, is deprecated in current Next.js: remove export const runtime = "edge" from routes. Proxy runs on Node.js, and Cache Components doesn't accept the runtime option at all. Vercel likewise recommends migrating from Edge to Node.js functions, and its docs note that from Next.js 16.3 routes and pages run on Node.js there regardless of the setting. On serverless platforms in general, remember that function instances are short-lived: a cache that works on your laptop may barely hit in production unless it is shared.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.Which feature still works in a static export?
  2. 2.You run four containers behind a load balancer. Users sometimes see "Failed to find Server Action". The likeliest cause?
  3. 3.A route still has `export const runtime = 'edge'` after upgrading. What should you do?

0 of 3 right so far. Get all three to finish this topic.