0
0
DockerHow-ToBeginner · 4 min read

How to Create a Dockerfile for Next.js Projects

To create a Dockerfile for a Next.js app, use a multi-stage build that first installs dependencies and builds the app, then creates a lightweight production image with the built files. This approach uses node images for building and node or alpine images for running the app efficiently.
📐

Syntax

A typical Next.js Dockerfile uses multi-stage builds with these parts:

  • FROM: Defines the base image (usually a Node.js image).
  • WORKDIR: Sets the working directory inside the container.
  • COPY: Copies files from your project to the container.
  • RUN: Runs commands like installing dependencies and building the app.
  • EXPOSE: Opens the port the app will listen on.
  • CMD: Defines the command to start the Next.js server.
dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]
💻

Example

This example Dockerfile builds a Next.js app and runs it in production mode on port 3000. It uses npm ci for clean installs and copies only necessary files to keep the image small.

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

FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]
Output
Starting Next.js server on http://localhost:3000
⚠️

Common Pitfalls

Common mistakes when creating a Dockerfile for Next.js include:

  • Not using multi-stage builds, which leads to large images.
  • Copying unnecessary files like node_modules from the host, causing conflicts.
  • Forgetting to expose the correct port (default is 3000).
  • Running npm start without building the app first.

Always build the app inside the container and copy only the build output and dependencies to the final image.

dockerfile
### Wrong approach (legacy):
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]

### Correct approach (multi-stage):
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]
📊

Quick Reference

Summary tips for Next.js Dockerfiles:

  • Use node:18-alpine for a small, secure base image.
  • Use multi-stage builds to separate build and runtime environments.
  • Run npm ci for clean installs based on package-lock.json.
  • Copy only necessary files to the final image.
  • Expose port 3000 and start the app with npm start.

Key Takeaways

Use multi-stage Docker builds to keep Next.js images small and efficient.
Always build the Next.js app inside the container before running it.
Copy only necessary files like build output and dependencies to the final image.
Expose port 3000 in the Dockerfile to match Next.js default server port.
Use lightweight base images like node:18-alpine for production.