Understanding how Docker builds images in layers — and how caching works — directly informs how to write more efficient Dockerfiles and diagnose unexpectedly slow builds.
What a Layer Actually Is
Each instruction in a Dockerfile (mostly RUN, COPY, ADD) creates a new layer — a layer represents the file system changes from that specific instruction, stacked on top of previous layers to form the complete image.
Viewing an Image's Layers
docker history myapp:latest
Shows each layer, its size, and the instruction that created it — useful for understanding where an image's size is actually coming from.
How Layer Caching Speeds Up Builds
Docker caches each layer — if a Dockerfile instruction and its inputs haven't changed since the last build, Docker reuses the cached layer instead of re-executing it, significantly speeding up rebuilds when only some instructions have actually changed.
Why Instruction Order Matters
# Less efficient caching
COPY . .
RUN npm ci
# More efficient caching
COPY package*.json ./
RUN npm ci
COPY . .
In the first version, ANY code change invalidates the cache for the (often slow) npm ci layer, since it comes after the full COPY. In the second version, npm ci only re-runs when the dependency manifest actually changes, not on every code change — a significant, common optimization.
Cache Invalidation Cascades
Once a layer's cache is invalidated (because its instruction or inputs changed), every subsequent layer's cache is also invalidated, even if those later instructions themselves didn't change — this is why ordering (least-frequently-changing instructions first) matters so much for build efficiency.
Forcing a Fresh Build Without Cache
docker build --no-cache -t myapp .
Useful when you suspect stale cache is causing an issue, or want to verify a build genuinely works from scratch.
Layers and Final Image Size
Each layer adds to the final image size — even if a later layer deletes files from an earlier layer, those files still exist in the earlier layer and contribute to overall image size (the deletion is itself a new layer, not a retroactive removal from history), which is part of why multi-stage builds (see Docker Multi-Stage Builds: Reducing Image Size) are so effective for size reduction.
Combining Instructions to Reduce Layer Count
RUN apt update && \
apt install -y curl git && \
rm -rf /var/lib/apt/lists/*
Combining related commands into a single RUN instruction (using &&) means cleanup happens within the same layer, actually reducing final size, rather than the cleanup being a separate later layer that doesn't retroactively shrink the earlier one.
Understanding Shared Layers Across Images
Images sharing a common base (like the same FROM node:20-alpine) share those base layers on disk — Docker doesn't duplicate identical layers across multiple images, which is part of why using consistent base images across your projects can save meaningful disk space.
Practical Takeaways for Dockerfile Writing
- Order instructions from least to most frequently changing
- Combine related RUN commands to minimize layer count and enable proper cleanup within the same layer
- Use multi-stage builds to exclude build-time-only content from the final image
Continue Reading
- How to Build Custom Docker Images with Dockerfile
- Docker Multi-Stage Builds: Reducing Image Size
- How to Clean Up Docker Disk Space (Images, Volumes, Build Cache)
Browse more articles in Docker & Containers.