output
Switches the build between a minimal self-contained server and a fully static site.
output?: 'standalone' | 'export'- Added in Next.js v12.0.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$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
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
output: 'standalone',
}
export default nextConfigWhen 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.
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.
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