CalcSnippets Search
Web 3 min read

Next.js `output: 'standalone'` Is the Build Setting You Should Use Before You Ship a Bloated Container for No Reason

A practical guide to Next.js standalone output so you can ship smaller production containers with only the files required to run the app instead of dragging your whole workspace into the image.

Why this setting matters: a lot of Next.js deploy images are larger and messier than they need to be because teams copy the whole project into production when the runtime only needs a subset.

Next.js supports standalone output so the production server bundle includes only the necessary runtime files plus a minimal server.js entry. If you are containerizing Next.js and still shipping oversized images full of unnecessary project baggage, this is one of the first settings worth fixing.

Turn on standalone output

In next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
}

module.exports = nextConfig

Then build:

npm run build

or:

pnpm build

Next.js will produce a .next/standalone directory containing the minimal app server output.

Why this helps in Docker

Without standalone output, teams often end up copying far too much into the final image:

  1. source files not needed at runtime
  2. development-only dependencies
  3. repo-level clutter
  4. toolchain artifacts

With standalone output, your final production image can focus on the minimal runtime set.

That usually means:

  1. smaller images
  2. faster pushes and pulls
  3. cleaner deploy artifacts
  4. less confusion about what production is actually running

A common multi-stage Docker pattern

Example:

FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

This is much cleaner than turning the final stage into a second full copy of the entire repository.

Why this is often overlooked

Developers see the app running locally and assume deployment shape is “good enough.” But runtime packaging matters:

  1. image size affects CI and deploy speed
  2. cleaner runtime artifacts reduce ambiguity
  3. smaller attack surface is usually better than larger

You do not need to become a container maximalist to care about this. You just need to avoid obvious waste.

Verify the runtime image instead of trusting the build blindly

After building the image, run it locally once:

docker build -t my-next-app .
docker run --rm -p 3000:3000 my-next-app

Then check the real concerns:

  1. does the app start with server.js
  2. are static assets present
  3. do required runtime environment variables still exist
  4. did you copy public and .next/static

A surprising number of “standalone” deployments fail because the build completed but the final image missed a runtime asset. One local container boot is much cheaper than learning that during deploy.

If you need env vars during the test, pass one or two explicitly:

docker run --rm -p 3000:3000 -e NODE_ENV=production my-next-app

Final recommendation

If you deploy Next.js in containers, turn on output: 'standalone' and build your final image around the standalone runtime instead of copying the whole project into production. It is one of the simplest ways to get a cleaner deploy without changing the app itself.

Sources

Keep reading

Related guides