A single-stage Dockerfile for a Next.js app ships the whole toolchain: dev dependencies, source files and build cache. Splitting the build into stages keeps only what the server needs at runtime.
Enable standalone output
With standalone output, Next.js traces the files the server actually imports and copies them into .next/standalone, including a minimal node_modules.
// next.config.ts
const nextConfig = {
output: "standalone",
};
export default nextConfig;The Dockerfile
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/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
USER node
EXPOSE 3000
CMD ["node", "server.js"]Why it matters
- Smaller images pull and deploy faster.
- Fewer packages in the final image means a smaller attack surface.
- Running as the node user limits what a compromised process can do.