Docker packages your Next.js app, its dependencies, and its runtime into a single, portable container image — useful for self-hosting or deploying to any cloud provider that supports containers. This lesson covers a production-ready setup.
The standalone Output Mode
Next.js includes a built-in output: "standalone" configuration specifically designed for Docker deployments. It produces a minimal folder containing only the files actually needed to run the app in production — including a trimmed node_modules — rather than requiring the entire project (dev dependencies included) inside the container image.
Combined with a multi-stage Dockerfile (building in one stage, copying only the final output into a lean runtime stage), this keeps container images significantly smaller and faster to deploy than a naive "copy everything" approach.
This single config option is the prerequisite for the minimal, production-ready Dockerfile pattern shown below.
A Minimal Multi-Stage Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
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"]
The builder stage installs dependencies and runs next build with full dev dependencies available.
The runner stage only copies the standalone output, keeping the final image small.
node server.js (generated by the standalone build) starts the production server directly.
Static assets (.next/static and public/) must be copied explicitly alongside the standalone folder.
Docker Deployment Cheat Sheet
Key files and settings for a Next.js Docker setup.
Item
Purpose
output: "standalone"
Produces a minimal, self-contained build output
Multi-stage Dockerfile
Keeps the final image small by separating build and runtime
.dockerignore
Excludes node_modules/.git from the Docker build context
EXPOSE 3000
Documents the port the container listens on
Environment variables
Passed at container runtime, not baked into the image
Using a .dockerignore File
Without a .dockerignore file, Docker copies your entire project directory (including node_modules and .git) into the build context, slowing down builds significantly. Excluding these directories mirrors what .gitignore already does for version control.
Secrets and configuration should be passed to the running container (via docker run -e or your orchestration platform's secret management), not baked into the image at build time — this keeps the same image usable across different environments (staging, production) with different configuration.
docker run -p 3000:3000 -e DATABASE_URL="postgres://..." my-next-app
Common Mistakes
Forgetting output: "standalone", resulting in a much larger and less efficient container image.
Not using a .dockerignore file, bloating the build context unnecessarily.
Baking secrets directly into the image instead of passing them at container runtime.
Using a single-stage Dockerfile that ships dev dependencies into the production image.
Key Takeaways
output: "standalone" produces a minimal build output tailored for containerized deployments.
A multi-stage Dockerfile keeps the final production image small and efficient.
A .dockerignore file excludes unnecessary files from the Docker build context.
Environment variables should be passed at runtime, not embedded into the image.
Docker gives you a portable deployment target usable across any container-supporting cloud provider.
Pro Tip
Test your Docker image locally with docker run before deploying it anywhere — confirming the standalone build actually starts and serves your app correctly in an isolated container catches configuration issues (like missing environment variables) much earlier than discovering them in a remote deployment.
You've completed the deployment section. Next, move into advanced topics, starting with internationalization for multi-language Next.js apps.