WarpBuild LogoWarpBuild Docs

Node.js with Next.js

Best practices for Dockerfile for Node.js with Next.js

🐳 Annotated Dockerfile for Node.js with Next.js:

# Use Node.js LTS as the base image for consistency and long-term support
FROM node:lts-slim AS base
 
# Stage 1: Install dependencies only when needed
FROM base AS deps
 
# Set working directory
WORKDIR /app
 
# Copy package.json and related files
COPY package.json package-lock.json* ./
 
# Install dependencies
RUN --mount=type=cache,target=/root/.npm \
    npm ci
 
# Stage 2: Build the application
FROM base AS builder
 
WORKDIR /app
 
# Copy dependencies
COPY --from=deps /app/node_modules ./node_modules
 
# Copy project files
COPY . .
 
# Next.js collects anonymous telemetry data - disable it
ENV NEXT_TELEMETRY_DISABLED=1
 
# Build the Next.js application
RUN --mount=type=cache,target=/root/.npm \
    npm run build
 
# Stage 3: Create production image
FROM base AS runner
 
WORKDIR /app
 
# Set to production environment
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
 
# Create a non-root user
RUN useradd -m nextuser
 
# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
 
# Set correct ownership
RUN chown -R nextuser:nextuser /app
 
# Switch to non-root user
USER nextuser
 
# Expose port
EXPOSE 3000
 
# Run the Next.js application
CMD ["npm", "start"]

🔍 Why these are best practices:

✅ Multi-stage builds

  • Smaller final images: Dependencies and build tools are discarded after use, reducing container size.
  • Security: Fewer files and tools mean a smaller attack surface.

✅ Using npm ci instead of npm install

  • Deterministic builds: Ensures exact versions from package-lock.json are used.
  • Faster than npm install: Bypasses dependency resolution for clean installations.
  • CI-friendly: Designed specifically for automated environments.

✅ Next.js specific optimizations

  • Standalone output mode: Creates a self-contained application that includes the Next.js server
  • Static assets are properly handled and copied to the right locations
  • Telemetry is disabled for privacy and performance

✅ Non-root user implementation

  • Security best practice: Running as a non-privileged user minimizes potential security risks
  • Follows principle of least privilege

🚀 Additional Next.js-specific configurations:

Enable standalone output

In your next.config.js file, ensure you have:

module.exports = {
  output: "standalone",
};

Set up environment variables properly

For environment variables that need to be available at build time:

# In the builder stage
ARG DATABASE_URL
ENV DATABASE_URL=${DATABASE_URL}

Optimizing for different Next.js deployment modes

For static export:

# For static export (if not using API routes or server components)
FROM base AS builder
# ...other steps...
RUN npm run build && npm run export
 
FROM nginx:alpine
COPY --from=builder /app/out /usr/share/nginx/html

Using Next.js with Docker Compose for development

version: "3"
services:
  nextjs:
    build:
      context: .
      target: deps # Only build up to the deps stage for development
    command: npm run dev
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"

By following these best practices, your Next.js applications will be containerized efficiently, securely, and with optimal performance for production deployments.

Last updated on