cf.completefrontend
Open lab My progress
THE NEXT.JS FIELD GUIDE

Deploying Next.js

Run a Next.js app four ways, a Node.js server, Docker, a static export or a platform's adapter, and see which features each one supports.

By the end, you can
  • 01
    Name the four ways to deploySay what runs when a request comes in for a Node.js server, a Docker container, a static export and a platform with an adapter.
  • 02
    Read what each way supportsUse the docs' tables to tell which features need a server, which need streaming, and which need a cache that every server shares.
  • 03
    Choose a way for a projectMatch a project's needs, like cookies, regenerated pages or no servers to run, to the way of deploying that fits.

One tea shop, four places to run it

Deploying an app means putting it on a computer that visitors can reach, and keeping it running there. For a Next.js app, it starts the same way every time: next build turns your project into the files a server or a host needs. What runs those files is your choice. The Next.js docs name four ways:

  • A Node.js server. Any computer that runs Node.js runs next start, Next.js's own server.
  • A Docker container. The same server, packed with Node.js and your app into one box that runs the same way everywhere.
  • A static export. No server of yours at all: next build writes plain files, and any web host sends them.
  • A platform with an adapter. A hosting company runs the app for you. Its adapter is code that reshapes the build for its computers.

Here is the tea shop, built once and run the first way. It has the kinds of pages earlier lessons built: a home page with a photo, a menu that's cached for an hour, a cart that reads a cookie, and a proxy.ts. This example is a real Next.js 16.4.3 project. It was built with next build, started with next start, and what the server sent back was recorded. Click a file in the tree to read it.

The tea shop on one Node.js serverNext.js
app/cart/menu/public/
app/page.tsx
import Image from "next/image"; export default function Home() {  return (    <main>      <h1>Tea shop</h1>      <Image src="/green-tea.jpg" alt="A cup of green tea" width={480} height={320} />      <p>Green tea: $4. Mint tea: $3.</p>    </main>  );}
Recorded from Next.js 16.4.3
$ next build▲ Next.js 16.4.3 (Turbopack)- Cache Components enabled- Partial Prefetching enabled   Creating an optimized production build ...✓ Compiled successfully  Running TypeScript ...  Finished TypeScript ...  Collecting page data ...✓ Generating static pages (5/5)  Finalizing page optimization ... Route (app)           Revalidate  Expire┌ ○ /├ ○ /_not-found├ ◐ /cart└ ○ /menu                     1h      1d ƒ Proxy (Middleware) ○  (Static)             prerendered as static content◐  (Partial Prerender)  prerendered as static HTML with dynamic server-streamed content $ next start▲ Next.js 16.4.3- Local:         http://127.0.0.1:3000- Network:       http://127.0.0.1:3000✓ Ready

Open the Terminal tab. Under $ next build, the route table lists every route and how it's made: ○ / and ○ /menu are prerendered as static content, /menu with a Revalidate of 1h, ◐ /cart is a static shell with a part streamed in for each request, and ƒ Proxy (Middleware) says proxy.ts runs on the server. Under $ next start, the server says it's Ready on port 3000. Then the Network tab holds the five answers that one process sent: the pages, the cart made for the request, and a photo the image optimizer resized.

The tea shop's project goes through next build once. Arrows lead from the build to four places it can run: a Node.js server running next start, which supports every feature; a Docker container with next start inside, which supports every feature; a static host that only serves files, with no code that runs per request; and a platform with an adapter, which supports what the platform supports.the projectnext buildNode.js serverruns next start: every featureDocker containernext start inside: every featureStatic hostonly files: no request-time codePlatform + adapterwhat the platform supports
One build, four ways to run it. A Node.js server and a Docker container both run next start, so both support every feature. A static export is only files, so nothing runs when a request comes in. A platform runs the build through its adapter, and supports what it was built to support.
Real-life analogyOne bakery's bread, four ways to sell it

A bakery bakes its bread once in the morning, and can sell it four ways. In its own shop, the baker can still bake a fresh loaf for a customer who asks. A food truck carries the same oven anywhere it parks. A supermarket shelf only holds loaves wrapped ahead of time: nobody there can bake to order. A market hall runs the stalls for many bakers, and each stall fits the hall's rules about what it can do.

In real life: The recipe and the morning's baking
In Next.js: Your project and next build
In real life: Your own shop, with an oven behind the counter
In Next.js: A Node.js server running next start
In real life: A food truck: the same oven, packed to park anywhere
In Next.js: A Docker container
In real life: Wrapped loaves on a supermarket shelf, no oven in sight
In Next.js: A static export: files only
In real life: A market hall that runs the stalls, with its own rules
In Next.js: A platform, and its adapter
The main idea

You build a Next.js app once, then choose what runs it. A Node.js server and a Docker container run next start, so they support every feature. A static export is only files, so only what was made during the build works. A platform runs your build through its adapter, and supports what that platform supports.

A Node.js server: next build, then next start

The first way is the one every project already has. Click package.json in the example's tree, one of the files marked create-next-app. Lines 7 and 8 are its build and start scripts: next build and next start. On any computer with Node.js, these three commands install, build and run the shop:

Run the shop on a computer with Node.jsShell
npm ci
npm run build
npm run start

Line 1 installs the exact packages the lockfile lists. Line 2 builds the app into the .next folder. Line 3 starts the server, which listens on port 3000 until you stop it (next start -p 8080 picks another port). The docs say this server supports every Next.js feature, and the recording shows several of them working in one process:

  • Static pages. / came with Cache-Control: s-maxage=31536000: the page was made during the build, and a shared cache like a CDN may keep it for a year.
  • Regenerated pages. app/menu/page.tsx is cached with "use cache" and cacheLife("hours"). Its answer says s-maxage=3600, stale-while-revalidate=82800: fresh for an hour, then served old while the server makes a new one in the background. That's Incremental Static Regeneration (Incremental Static Regeneration), and only a running server can do it.
  • Streaming. /cart came with private, no-cache, no-store…, and its static shell first, with Loading your cart…, then the part that read the cookie (Partial Prerendering).
  • Proxy. /teas has no page, yet it answered with the home page: proxy.ts rewrote the request on line 5 before any page ran (Proxy).
  • Image Optimization. The last answer is the photo as WebP, 640 pixels wide, made by the server on request: X-Nextjs-Cache: MISS. That needs the sharp package, which npm ci installed with Next.js (Optimizing images).

Three more things come with running the server yourself. Environment variables that a page reads at request time are read when the request comes in, so one build can run with different values in each environment (Server-only code and environment variables). after() callbacks run once the answer has gone (Work after the response), so the server must be stopped gracefully: sent SIGTERM or SIGINT, then given time. The docs recommend 10 to 30 seconds, while it finishes the requests in flight and the pending callbacks. And the docs recommend a reverse proxy, like nginx, in front of the server rather than exposing it to the internet directly. Self-hosting sets all of that up.

Docker: the same server in a container

A server needs the right Node.js, the right packages and your built app, set up the same way on every computer that runs it. Docker packs all of that into one file:

  • A Dockerfile is a list of steps that sets up the app, one after the other.
  • docker build runs the steps and saves the result as an image: a snapshot of a small Linux system with Node.js, the packages and the built app inside.
  • docker run starts a container from the image: a running copy, kept apart from the computer around it. One image can start many containers, on any computer or cloud that runs Docker, including orchestrators like Kubernetes.

This is the simplest Dockerfile that runs the tea shop. It isn't run on this page, and it isn't the one to ship:

Dockerfile: the simplest one that runs the shopDockerfile
FROM node:24.13.0-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start"]

Line 1 starts from an image with Node.js already in it, the version the official example uses. Line 2 makes /app the folder every later step works in. Lines 3 and 4 copy only the package files and install from the lockfile. Because they come before the rest of the code, Docker can reuse that step when only your code changes. Line 5 copies the rest of the project, and line 6 runs next build. Line 7 notes the port the server listens on, and line 8 is the command a container runs when it starts: npm run start, so next start. Two commands build the image and start one container:

Build the image, then start a container from itShell
docker build -t tea-shop .
docker run -p 3000:3000 tea-shop

Line 1 builds the image and names it tea-shop. Line 2 starts a container and connects the computer's port 3000 to the container's, so localhost:3000 reaches the shop. Inside, it's the same server as before, so the docs say a Docker deployment supports every feature too.

This image is bigger than it needs to be. It holds every package, the development tools included, and the whole project. The docs' official example uses output: "standalone", which makes next build write a small folder with only the files the server needs, and copies only that into the last stage of the image. Self-hosting builds that Dockerfile and records what the standalone folder holds. One more note from the docs: while you develop on a Mac or on Windows, run npm run dev directly on your computer rather than in Docker. It's faster there.

A static export: files on any web host

A static export leaves the server out. With output: "export" in next.config.ts, next build writes every page into a folder called out, as files. Any web server that sends files can host them: Amazon S3, nginx, Apache, GitHub Pages. The site you're reading is a Next.js app exported this way.

Two sides. Left, a Node.js server: the browser asks for slash cart with a cart cookie, the server runs the cart page's code, reads the cookie, and sends a page that says In your cart: Mint tea. Right, a static host: the browser asks for slash cart, and the host sends the file cart.html, the same file for every visitor; any cart code runs later, in the browser.Node.js serverGET /cart, cookie cart=mintnext startruns the cart's codeIn your cart: Mint teamade for this visitorStatic hostGET /carta folder of filesfinds cart.htmlthe same file for everyoneno code runs on the host
On a server, the cart page's code runs for each request, so it can read the visitor's cookie. A static host only finds the file for the address and sends it, the same bytes to everyone. Anything about one visitor has to happen in the browser, after the file arrives.

The price is everything that needs code to run when a request comes in. Try it with a smaller tea shop: a home page, and a cart. Each button below is one version, and each was built with real Next.js 16.4.3. Before you click, guess which ones build.

Playground: what does a static export accept?
The small tea shop, with this version of next.config.ts and its cartNext.js
app/cart/
next.config.ts
import type { NextConfig } from "next"; const nextConfig: NextConfig = {  /* config options here */  cacheComponents: true,  partialPrefetching: true,}; export default nextConfig;
Recorded from Next.js 16.4.3
$ next build▲ Next.js 16.4.3 (Turbopack)- Cache Components enabled- Partial Prefetching enabled   Creating an optimized production build ...✓ Compiled successfully  Running TypeScript ...  Finished TypeScript ...  Collecting page data ...✓ Generating static pages (4/4)  Finalizing page optimization ... Route (app)┌ ○ /├ ○ /_not-found└ ◐ /cart ○  (Static)             prerendered as static content◐  (Partial Prerender)  prerendered as static HTML with dynamic server-streamed content
Try it yourself
For a server

No output option: the build is for a server. The cart reads its cookie on the server, so the build prints ◐ /cart, and the Network tab shows the cart made for one request.

Every version was built with next build from Next.js 16.4.3; the Terminal shows what it printed. Only next.config.ts and the cart's files change. Reset goes back to the first version.

Here is what each version shows:

  1. For a server. The cart's CartItem reads the cookie on line 5 of app/cart/page.tsx, inside Suspense. The build prints ◐ /cart, and the server makes that part for each request.
  2. Export, cookie on the server. The build stops on /cart: it couldn't be rendered statically because it used cookies(). In an export, every page must be made during the build, and no cookie exists then.
  3. Export, cookie in the browser. The cart now reads the cookie in a Client Component, after the page has loaded: app/cart/cart-item.tsx, shown below. All four pages prerender. Then the export itself stops: Invariant: PPR cannot be enabled in export mode. In Next.js 16.4.3, a static export can't have Cache Components on.
  4. Export, Cache Components off. With cacheComponents and partialPrefetching removed, the build prints ○ /cart and writes out: index.html, cart.html and 404.html, .txt files that hold each page's RSC payload for the router, and the JavaScript in _next/static. That folder is the whole site.
app/cart/cart-item.tsx: the cart read in the browserTSX
"use client";

import { useEffect, useState } from "react";

export default function CartItem() {
  const [tea, setTea] = useState<string | null>(null);
  useEffect(() => {
    setTea(document.cookie.match(/(?:^|; )cart=([^;]*)/)?.[1] ?? "");
  }, []);
  if (tea === null) return <p>Loading your cart…</p>;
  return <p>{tea ? `In your cart: ${tea}` : "Your cart is empty."}</p>;
}

Line 1 makes CartItem a Client Component (Client Components). Line 6 starts with null, so the page made during the build shows Loading your cart… on line 10. The Effect on lines 7 to 9 runs in the browser and reads the cookie from document.cookie, and line 11 shows it. Every visitor gets the same file; the browser fills in their own cart.

The static exports guide lists what isn't supported, because it needs a server: cookies and other request-time APIs, proxy.ts, rewrites, redirects and headers from next.config.ts, Incremental Static Regeneration, Image Optimization with the default loader, Draft Mode, Server Actions, intercepting routes, Route Handlers that read the request, and dynamic routes whose addresses generateStaticParams doesn't list (generateStaticParams). Static exports, in this stage, goes further: images, single-page apps, and what to do instead of each.

Platforms and adapters

A platform is a hosting company that runs your app on its computers, so you don't run servers yourself: Vercel, Netlify, Cloudflare, AWS Amplify, Firebase App Hosting, Deno Deploy and others. A platform often splits an app into parts: functions that run on demand, files on its CDN, rules that send each request to the right part. Something has to turn next build's output into those parts. That's an adapter.

next build's output goes into an adapter, named by adapterPath in next.config.ts. The adapter turns it into the parts a platform runs: functions that render pages, files for the platform's CDN, and routing rules.next buildadapteradapterPathfunctions that renderfiles for its CDNrouting rules
An adapter runs at the end of next build and reshapes its output for one platform: code that renders, files its CDN serves, the rules that send each request to the right place. Where cached pages and data live is the other half, configured with cacheHandler and cacheHandlers.

Next.js has a public Build Adapters API for this, stable since Next.js 16.2. An adapter is a module named by adapterPath in next.config.ts, or by the NEXT_ADAPTER_PATH environment variable, which lets a platform set it for you:

next.config.ts: a platform's adapterTypeScript
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
  adapterPath: require.resolve("./my-adapter.js"),
};

export default nextConfig;

Line 6 names the adapter. It runs during next build and writes what its platform needs. The docs list two kinds of platform support:

  • Verified adapters are open source and run Next.js's full compatibility test suite, and live under the Next.js GitHub organization. On the docs' Deploying page, those are Vercel's and Bun's. Vercel's adapter uses the same public API as everyone else's.
  • Other platforms have their own Next.js integrations, not built on the public API and not verified, so what works varies: the docs name Appwrite Sites, AWS Amplify Hosting, Cloudflare, Deno Deploy, Firebase App Hosting and Netlify. Cloudflare and Netlify are working on verified adapters.

The docs separate two ideas. Functional fidelity means every feature works correctly; the test suite checks it. Performance fidelity means a feature is as fast as it can be, like a static shell served from a CDN close to the visitor. Platforms differ most in the second. Adapters and other platforms, later in this stage, looks at Vercel, Netlify, Cloudflare and OpenNext on AWS in turn.

Which features each way supports

The docs' Deploying page sums up the four ways in one table. Each row is one way:

The four ways to deploy
Way to deployWhat runs when a request comes inFeatures
A Node.js servernext start, which npm run start runs, after next build.All.
A Docker containerThe same next start (or the standalone server.js), inside a container.All.
A static exportNothing of yours. A web server sends files from the out folder.Limited: nothing that needs a server.
A platform's adapterWhatever the platform runs, made from the build by its adapter.It varies. Verified adapters run Next.js's own test suite.

Most features' pages in the docs end with a Platform support table with the same four columns. Here they are side by side. Image Optimization, Partial Prerendering, Server Actions and Route Handlers have no such table, so their rows come from the Deploying page and the self-hosting, static exports and PPR platform guides. Each row is one feature, and Platform-specific is the docs' word for "ask your platform":

Features by deployment type
FeatureNode.js serverDocker containerStatic exportAdapters
Incremental Static RegenerationYes.Yes.No.Platform-specific.
Image Optimization with the default loaderYes, with sharp installed.Yes, with sharp installed.No. Use a custom loader, or unoptimized.Depends on the platform.
proxy.tsYes.Yes.No.Platform-specific.
Cache Components ("use cache")Yes.Yes.No.Platform-specific.
Partial Prerendering (a static shell, then streamed parts)Yes: next start sends the shell and renders the rest in one response.Yes.No. In 16.4.3 the export stops while Cache Components is on.Depends on the platform. Some serve the shell from a CDN and resume at the server.
Streaming (loading.tsx, Suspense)Yes.Yes.No.Platform-specific.
Server ActionsYes.Yes.No.Depends on the platform.
Route HandlersYes, every method.Yes, every method.Only GET handlers made into files during the build (dynamic = "force-static"), none that read the request.Depends on the platform.
after()Yes, if the server is stopped gracefully.Yes, if the container is stopped gracefully.No.Platform-specific.

The pattern is the one the playground showed: what needs code at request time works wherever next start runs, and not in a static export. Two details matter once there's more than one server, or something between the server and the visitor. The docs' Deploying to Platforms guide has a matrix for them. Each row is one feature: does it need responses to stream through, and should every instance of the server share one cache?

What each feature needs from the hosting
FeatureNeeds streamingA cache shared by every instance
Server ComponentsRequired.No.
ISR, after a timeNo.Recommended. Each instance works alone without one.
ISR, on demand (revalidateTag)No.Recommended. A tag expired on one instance must reach the others.
Partial PrerenderingRequired.Recommended.
Cache ComponentsRequired.Recommended.
ProxyNo.No.
Server ActionsRequired.No.
after()No. It needs a graceful shutdown.No.

Streaming means the answer can arrive in pieces, like the cart's shell and then its cookie part. Nothing between the server and the browser may hold the pieces back until the end (Streaming). A host that does still works, the docs say, but the visitor waits for the whole page. A shared cache matters with several instances: without one, a page regenerated on one instance stays old on the others.

Partial Prerendering has one more option. next start sends a route's static shell and renders the rest in the same response. A CDN can also keep the shell close to visitors and ask the server for only the rest: the docs call this resuming, a POST with the header next-resume: 1 and the shell's saved state as its body. It's only faster, never required. Every feature in these tables works on a single next start.

Choosing a way for each project

Each row is one project, what it needs, and a way that fits it:

Four projects, four choices
ProjectWhat it needsA good fit
The tea shopA cart that reads a cookie, a menu that's regenerated, photos resized on request.A Node.js server or a Docker container, or a platform whose adapter supports these features.
A tea blog on a host that only sends filesPosts written ahead of time. Nothing about one visitor on the server.A static export. In Next.js 16.4.3, with Cache Components off.
A company that runs every app in KubernetesThe same container image in every environment, many copies at once.A Docker container, built with the standalone output.
A small team with nobody to run serversNo servers to patch or watch.A platform, ideally with a verified adapter.

The first question is always the same: does anything need code to run when a request comes in? Sort these needs of the tea shop:

Does this need a server at request time?
  • The cart page reads the visitor's cookie in a Server Component.
  • The menu is made again in the background once its hour has passed.
  • proxy.ts sends the old /teas address to the home page.
  • /_next/image resizes the photo for each screen.
  • The home page lists teas and reads nothing from the request.
  • A Client Component reads the cart cookie in the browser.
  • A dynamic route whose every address is listed by generateStaticParams.
  • Photos come from an image service through a custom loader.
Try it yourself
0 of 8 correct

Sort each need: does it need a server running when the request comes in, or can a host that only sends files serve it?

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

  • "Next.js only runs on Vercel." No. The docs' first way is any computer with Node.js, and it supports every feature. Vercel is one platform, with one adapter, built on the same public API as the others.
  • "Docker supports fewer features than a server." No. The container runs the same server. What it changes is how the server is packed and started.
  • "A static export is a smaller build of the same app." No. It's a different kind of app: no code of yours runs when a request comes in. The playground's builds stopped on the cookie, and on Cache Components.
  • "A static export can't have anything per visitor." It can, in the browser. The exported cart reads its cookie in a Client Component, after the file arrives.
  • "Any platform supports everything." Not necessarily. The docs say support varies; verified adapters run the test suite, so you can see what works.
  • "Features need a CDN or edge servers." No. The docs say one next start handles every feature correctly. A CDN, a shared cache and edge servers make it faster, and keep many instances in step.

Practice exercises

These exercises are about Next.js projects, which can't run inside this page. Answer first, then use the hints.

Exercise 1 · Warm-upBuild and start the shop

This is the tea shop's package.json, as create-next-app wrote it. Which two scripts put the shop on a Node.js server?

Starter codeJSON
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "16.4.3",
    "react": "19.3.0",
    "react-dom": "19.3.0"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "typescript": "^5"
  }
}

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upRead the export's error

    This cart page is built with output: "export". The build stops. Which function does its error name?

    Starter codeTSX
    import { Suspense } from "react";
    import { cookies } from "next/headers";
    
    async function CartItem() {
      const tea = (await cookies()).get("cart")?.value;
      return <p>{tea ? `In your cart: ${tea}` : "Your cart is empty."}</p>;
    }
    
    export default function CartPage() {
      return (
        <main>
          <h1>Your cart</h1>
          <Suspense fallback={<p>Loading your cart…</p>}>
            <CartItem />
          </Suspense>
        </main>
      );
    }
    

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind the cart in the export

      With this cart and Cache Components off, the export builds. Which file in out does a host send when someone asks for /cart?

      Starter codeTSX
      "use client";
      
      import { useEffect, useState } from "react";
      
      export default function CartItem() {
        const [tea, setTea] = useState<string | null>(null);
        useEffect(() => {
          setTea(document.cookie.match(/(?:^|; )cart=([^;]*)/)?.[1] ?? "");
        }, []);
        if (tea === null) return <p>Loading your cart…</p>;
        return <p>{tea ? `In your cart: ${tea}` : "Your cart is empty."}</p>;
      }
      

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticePredict the menu's Cache-Control

        On the Node.js server, which Cache-Control header does /menu come with?

        Starter codeTSX
        import { cacheLife } from "next/cache";
        
        export default async function MenuPage() {
          "use cache";
          cacheLife("hours");
          return (
            <main>
              <h1>Menu</h1>
              <p>Mint tea: $3. Green tea: $4.</p>
            </main>
          );
        }
        

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeChoose for a tea blog

          The tea shop's owner writes a small tea blog. Posts change once a week, nothing depends on who's reading, and it will live on a school's web host that only sends files. Which way of deploying fits?

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeStopped too soon

            A host stops the shop's container one second after sending it SIGTERM, every time it deploys a new version. Answers already sent reach their visitors. Which Next.js feature can lose work?

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, ask what runs when a request comes in, and where.

              The Deploying Next.js quiz · 8 questionsScore: first tries count
              1. Question 1 of 8Which two ways of deploying does the docs' Deploying page say support every Next.js feature?

                Choose an answer to see the explanation.

              2. Question 2 of 8What does a Docker container change about which features work?

                Choose an answer to see the explanation.

              3. Question 3 of 8The tea shop's cart page reads a cookie with cookies(). What happens when you build it with output: "export"?

                Choose an answer to see the explanation.

              4. Question 4 of 8In Next.js 16.4.3, the cart now reads its cookie in the browser, and next.config.ts still has cacheComponents: true with output: "export". What does the build print?

                Choose an answer to see the explanation.

              5. Question 5 of 8What is an adapter, in the docs' Build Adapters API?

                Choose an answer to see the explanation.

              6. Question 6 of 8Which of these does the docs' feature matrix say needs streaming responses?

                Choose an answer to see the explanation.

              7. Question 7 of 8What does after() need from the server it runs on?

                Choose an answer to see the explanation.

              8. Question 8 of 8What makes an adapter "verified"?

                Choose an answer to see the explanation.

              Key takeaways

              • You build once with next build. Then a Node.js server, a Docker container, a static host or a platform runs the result.
              • next start supports every feature: static and regenerated pages, streaming, proxy.ts, the image optimizer, Cache Components and after(). A Docker container runs the same server.
              • A static export writes out, a folder of files. Nothing of yours runs per request, so cookies, ISR, proxy, Server Actions and the default image loader don't work there. In Next.js 16.4.3, it also needs Cache Components off.
              • A platform runs the build through its adapter (adapterPath). Verified adapters are open source and run Next.js's test suite; others vary.
              • With several instances, the docs recommend a shared cache, and streaming must pass through every proxy. after() needs a server that's stopped gracefully.

              Remember the one-liner.
              Build once, then ask what must run per request: if anything does, a server runs it; if nothing does, files are enough.

              Read it in Next.js's own code

              These links point at release v16.4.3, the version every example on this page was built with. The error the third playground version hit is thrown in lines 903 to 907 of export/index.ts, when a static export finds cacheComponents on. The adapter types live in build/adapter/build-complete.ts. The docs' official Docker example is examples/with-docker.

              Coming next: Self-hosting. It runs the shop on servers you manage: the standalone output, a production Dockerfile, a CDN in front, a cache shared by many instances, and deployments that don't break open pages.

              CompleteFrontend Clear concepts. Working examples.