Before (1.2GB) vs After (180MB)
Before
Dockerfile
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/server.js"]After (multi-stage)
Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]Core Optimization Principles
1. Layer cache order
Dockerfile
COPY package*.json ./
RUN npm ci
COPY src/ ./src/2. A .dockerignore is essential
CODE
node_modules
.git
.env
*.log
dist
coverage3. Combine RUN commands
Dockerfile
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*4. Alpine-based images
| Image | Size |
|---|---|
node:20 | 1.1GB |
node:20-slim | 240MB |
node:20-alpine | 140MB |
BuildKit cache mounts
Dockerfile
RUN --mount=type=cache,target=/root/.npm \
npm ciBash
DOCKER_BUILDKIT=1 docker build .Analyzing image size
Bash
docker history myapp:latest
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive myapp:latestEditorial note
AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us
Topic-related official docs (auto-linked · not per-claim sources)Docker documentation ↗
Questions & answers
Ask a question about this guide. We'll review and reply.