π³ Docker Image Optimization Guide β The Ultimate Cheat Sheet π
Optimize your Docker images for faster builds, smaller size, better caching, and production readiness. Letβs go!
π§± 1. Use a Small & Specific Base Image π₯
β Do This:
# Use lightweight Alpine variant
FROM node:20-alpine
β Avoid This:
# Heavy image β more layers, longer build times
FROM ubuntu
π Why?
- Smaller base = smaller image.
- Alpine images are ~5MB vs Ubuntuβs ~100MB.
- Smaller size = faster download, upload, deploy.
πͺ 2. Order Instructions for Layer Caching π
β Do This:
# Caches `npm install` unless package.json changes
COPY package*.json ./
RUN npm install
# Copy rest of the source after deps are installed
COPY . .
β Avoid This:
COPY . .      # π invalidates cache if any file changes
RUN npm install
π Why?
Docker caches layers. Changing a later step invalidates all subsequent layers. Put stable steps early for faster rebuilds.
  
  
  π§Ή 3. Remove Unnecessary Files with .dockerignore π«
  
  
  β
 Example .dockerignore:
node_modules
Dockerfile
.dockerignore
.git
npm-debug.log
π Why?
It prevents Docker from copying unnecessary files into the build context. Less context = faster build and smaller image.
ποΈ 4. Use Multi-Stage Builds π§ͺ
β Example:
# Stage 1: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# Stage 2: Runtime
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app .
EXPOSE 8000
CMD ["npm", "start"]
π Why?
- Separate build dependencies from runtime.
- Final image contains only whatβs needed to run the app.
- Reduces image size by up to 70%.
π§Ό 5. Remove Unused Dependencies π§Ή
  
  
  β
 Use --production for Node.js:
RUN npm ci --only=production
OR
npm prune --production
π Why?
Avoid bundling dev tools and test libraries into your production image.
π¦ 6. Combine RUN Commands π
β Do This:
RUN apk add --no-cache bash curl && \
    rm -rf /var/cache/apk/*
β Donβt Do:
RUN apk add bash
RUN apk add curl
π Why?
Each RUN creates a layer. Combining reduces total layers = smaller image size.
  
  
  π 7. Use --no-cache for Package Managers π₯
β Alpine:
RUN apk add --no-cache curl
β APT (Debian/Ubuntu):
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
π Why?
Avoids unnecessary cache files and reduces image size.
π 8. Avoid Root User (Security Best Practice) π
# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
π Why?
Running as root inside containers is risky. Use non-root users for security.
πͺ 9. Clean Up Temporary Files π§Ό
RUN npm install && \
    npm cache clean --force
π Why?
Removes package cache after install to reduce bloat.
  
  
  πͺ 10. Use Specific Tags (Not latest) π―
FROM node:20.11.1-alpine
π Why?
Using latest can break builds if the base image updates and introduces changes. Always pin versions for reliability.
π 11. Scan for Vulnerabilities π§¬
docker scan my-node-app
Or use:
- Docker Scout
- Trivy (Aqua Security)
- Snyk
π§ͺ 12. Analyze Image Size and Layers π
docker image inspect my-node-app
docker history my-node-app
Or use tools like:
- 
Dive: dive my-node-app
- 
DockerSlim: docker-slim build my-node-app
π§ Final Pro Tips π‘
| Tip | Benefit | 
|---|---|
| Use npm ciinstead ofnpm install | Faster and more reliable | 
| Group COPYsteps wisely | Better cache usage | 
| Avoid adding .envor secrets | Security risk | 
| Label images ( LABEL maintainer=...) | Better documentation | 
| Run production builds with NODE_ENV=production | Removes dev dependencies | 
π Sample Optimized Dockerfile for Node.js App
# π· Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# β¨ Stage 2: Runtime
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app .
ENV NODE_ENV=production
RUN npm prune --production
EXPOSE 8000
CMD ["npm", "start"]
 


 
    
Top comments (0)