{DT}DevToolkit

Dockerfile Optimizer for Node.js

Analyze your Dockerfile for Node.js best practices. Get suggestions for smaller images, better security, and faster builds.

Paste Your Dockerfile

Dockerfile Best Practices for Node.js

Use Alpine Images

Alpine-based images (node:20-alpine) are ~100MB vs ~1GB for full images. They include musl libc instead of glibc, which works for most Node.js applications. If you need native dependencies, consider node:20-slim (Debian-based, ~200MB).

Multi-Stage Builds

Use multi-stage builds to separate build dependencies from runtime. This keeps your final image small by excluding TypeScript, build tools, and dev dependencies.

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --omit=dev
CMD ["node", "dist/server.js"]

Layer Caching

Docker caches layers top-to-bottom. Copy package.json first, install dependencies, then copy source files. This way, npm install is cached when only source code changes.

Security Best Practices

  • Non-root user: Run as the built-in node user or create one
  • Pin versions: Use specific tags like node:20.10.0-alpine
  • Use npm ci: For reproducible builds from package-lock.json
  • Scan images: Use docker scout or Trivy for vulnerabilities

Production Optimizations

  • Set NODE_ENV=production for optimized runtime behavior
  • Use npm ci --omit=dev to exclude dev dependencies
  • Add healthchecks for container orchestration
  • Use node directly instead of npm start for proper signal handling
  • Clear npm cache after install to reduce image size

Common Mistakes

  • Using :latest tag (unpredictable builds)
  • Running as root (security risk)
  • Copying all files before npm install (breaks caching)
  • Including dev dependencies in production image
  • Not setting NODE_ENV=production