output

Switches the build between a minimal self-contained server and a fully static site.

Signature
output?: 'standalone' | 'export'
  • Added in Next.js v12.0.0

Parameters

ParameterTypeDescription
$outputoptional'standalone' | 'export'= undefined'standalone' writes .next/standalone containing a minimal server.js and only the traced node_modules, deployable without npm install. 'export' writes an out folder of HTML, CSS and JS servable by any static host. Unset leaves the default build, which requires next start and installed dependencies.

Errors

With output: 'export', using cookies(), Draft Mode, Server Actions, rewrites, redirects, headers, proxy, ISR, intercepting routes, or a dynamic route without generateStaticParams errors at build time.

Changelog

  • PHP v14.0.0next export removed in favour of output: 'export'.
  • PHP v13.4.0App Router static export support, including Server Components and Route Handlers.
  • PHP v13.3.0next export deprecated and replaced with output: 'export'.

Two unrelated modes share one key. 'standalone' uses output file tracing to copy only the files each route actually loads into .next/standalone, so a Docker image can drop node_modules entirely. 'export' gives up the server altogether and emits one HTML file per route.

When to reach for it

  • Building a small container image for Kubernetes or Fly.
  • Publishing to GitHub Pages, S3 or any plain static host.
  • Trimming a deployment bundle that is dominated by dev dependencies.

What trips people up

Standalone does not copy public/ or .next/static — the assumption is a CDN serves them. Miss that step and the site loads with no CSS and no images. Copy them by hand after next build, and start the app with node .next/standalone/server.js rather than next start. In a monorepo, tracing is rooted at the project directory, so shared packages above it need outputFileTracingRoot. Native binaries such as sharp are sometimes missed and need outputFileTracingIncludes. For 'export', the whole server-dependent half of the framework is off the table — the failure arrives as a build error, not a runtime surprise.

Example

Example · typescript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'standalone',
}

export default nextConfig

When to use it

  • Produce a slim Docker image that runs without installing dependencies
  • Publish a marketing site to GitHub Pages as plain HTML
  • Cut deployment size in a monorepo by tracing only what each route imports
  • Run the app behind a CDN that serves _next/static directly

Frequently asked questions

Why does my standalone build have no CSS or images?

Because public/ and .next/static are deliberately not copied into .next/standalone — Next.js assumes a CDN serves them. Copy them into standalone/public and standalone/.next/static after next build and server.js will serve them.

What can't I use with output: 'export'?

Anything needing a server or a request: cookies(), Draft Mode, Server Actions, rewrites, redirects, headers, proxy, ISR, intercepting routes, Route Handlers that read the request, dynamic routes without generateStaticParams, and the default image loader.

How do I start a standalone build?

Run node .next/standalone/server.js, not next start. Set PORT and HOSTNAME as environment variables to control the bind address, for example PORT=8080 HOSTNAME=0.0.0.0 node server.js.

More examples

Standalone in a Dockerfile

The two extra COPY lines are the step people miss. .next/standalone contains server.js and the traced node_modules only; once public/ and .next/static are copied to standalone/public and standalone/.next/static, server.js serves them automatically. PORT and HOSTNAME are read by the minimal server at startup, which is how you bind to something other than localhost:3000.

Example · dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

# server.js does not include these two directories
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static

ENV PORT=8080 HOSTNAME=0.0.0.0
EXPOSE 8080
CMD ["node", "server.js"]

Static export with the required companions

A static export writes one HTML file per route into out (renamed to dist here). Because there is no server, the default image optimizer is unavailable — either set unoptimized or configure a custom loader pointing at an external service. trailingSlash: true changes the emitted filenames to directory-style index.html, which is what most static hosts and CDNs expect.

Example · typescript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'export',

  // /me -> /me/ and /me.html -> /me/index.html
  trailingSlash: true,

  // out -> dist
  distDir: 'dist',

  images: {
    // the default optimizer needs a server
    unoptimized: true,
  },
}

export default nextConfig

Discussion

  • Be the first to comment on this lesson.