Atharva Unde
~/writing/ docker-layers-caching-multi-stage-explained

Docker Layers, Caching & Multi-Stage Builds Explained

Docker Layer Caching: How Docker builds work, multi-stage builds, build optimization, and reducing image size with efficient layer management strategies.

Atharva UndeFeb 12, 2024 · 15 min readDocker

This is where Docker optimization gets really interesting. Understanding layers, leveraging caching, and using multi-stage builds are the keys to creating production-ready, efficient container images.

01Understanding Docker Layers

Each instruction in your Dockerfile creates a new layer. These layers are stacked on top of each other, and Docker uses a copy-on-write filesystem to manage them efficiently.

Key concepts about layers:

  • Layers are immutable once created
  • If you delete a file in a later layer, it still exists in the previous layer
  • Layers are cached and reused between builds
  • Smaller layers = faster builds and pulls

Combining Commands

dockerfile
# Each RUN creates a new layerRUN apt-get updateRUN apt-get install -y curlRUN apt-get install -y gitRUN rm -rf /var/lib/apt/lists/* # Better: Combine into one layerRUN apt-get update && \    apt-get install -y curl git && \    rm -rf /var/lib/apt/lists/*

By combining commands, you reduce the number of layers and ensure cleanup happens in the same layer as file creation.

02Build Caching

Docker caches each layer during builds. If a layer hasn't changed, Docker reuses the cached version, dramatically speeding up subsequent builds.

Caching Strategy

dockerfile
# Not cache-friendlyCOPY . .RUN npm install # Cache-friendlyCOPY package*.json ./RUN npm installCOPY . .

By copying package.json first and running npm install before copying the rest of the code, we ensure that dependencies are only reinstalled when package.json changes, not on every code change.

Pro Tip: Order your Dockerfile instructions from least to most frequently changing. Put stable layers at the top and volatile ones at the bottom.

03Multi-Stage Builds

Multi-stage builds are the ultimate optimization technique. They let you separate build environment from runtime environment, copying only what you need for production.

dockerfile
# Build stageFROM node:24-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build # Production stageFROM node:24-alpineWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesEXPOSE 3000CMD ["node", "dist/index.js"]

Benefits of Multi-Stage Builds

  • Smaller Images: Final image contains only runtime dependencies
  • Better Security: No build tools or source code in production
  • Cleaner Separation: Build logic separated from runtime
  • Single Dockerfile: No need for separate build and runtime Dockerfiles

04Advanced Patterns

1. Multiple Build Stages

You can have more than two stages. For example: dependencies → build → test → production. Each stage can be optimized independently.

2. Build Stage with Distroless

Build on a full image (Ubuntu/Debian) and copy artifacts to a distroless or scratch image for maximum security and minimal size.

3. Development vs Production

Use --target flag to build different stages: docker build --target builder for dev, default stage for prod.

05Optimization Checklist

  • ✅ Use appropriate base images (Alpine, slim, distroless)
  • ✅ Leverage build caching by ordering instructions correctly
  • ✅ Combine RUN commands to reduce layers
  • ✅ Use multi-stage builds to separate build and runtime
  • ✅ Use .dockerignore to exclude unnecessary files
  • ✅ Clean up in the same layer where files are created
  • ✅ Install only production dependencies in final stage
  • ✅ Use specific version tags, not latest

06Real-World Results

With these techniques, you can typically achieve:

  • 50–90% reduction in image size
  • 10x faster builds with proper caching
  • Significantly improved security posture
  • Faster deployments and scaling

Example: A Node.js app can go from 1.2GB (node:latest) to 150MB (node:alpine with multi-stage) to as low as 50MB (distroless)!

07Tools for Analysis

  • dive: Analyze Docker images layer by layer
  • docker history: View layer sizes and commands
  • docker inspect: Get detailed image metadata
  • hadolint: Lint your Dockerfiles for best practices

08Conclusion

Mastering Docker layers, caching, and multi-stage builds is essential for production-grade containers. These techniques not only make your images smaller and faster but also more secure and maintainable.

Start applying these patterns today, and watch your build times drop and deployment speeds soar!

This concludes our Docker for Dummies series. I hope you found these practical guides helpful for your containerization journey!


DockerlayersDocker cachingmulti-stage buildsDocker build optimizationlayer caching strategyDockerfile best practicesbuild performanceimage size reductionDocker BuildKit

Keep reading

All posts