Course contentsShow
← Docker, Kubernetes & CI/CD
Lesson 125 of 8022. Docker Image LifecycleFree lesson

Optimizing Cache Layers Across Stages

You will order your multi-stage instructions to ensure that slow build steps are cached independently from frequently changing application source code.

In this lesson, you’ll learn how to order your multi-stage instructions so that expensive, slow-to-build dependencies are cached separately from your frequently changing application source code.

The Strategy: Separate the Stable from the Volatile

Docker builds images layer-by-layer. If a layer changes, Docker invalidates that layer and every subsequent layer. To optimize, we must isolate "slow" steps (like installing system libraries or downloading project dependencies) from "fast" steps (like copying your local source code).

In a multi-stage build, we achieve this by splitting the dependency installation into a dedicated build stage.

Putting it into Practice

Imagine a Node.js application. Installing node_modules takes minutes, while modifying a single JavaScript file takes milliseconds. If you COPY . . before running npm install, your cache is invalidated every time you save a file. Instead, follow this pattern:

# Stage 1: Dependency builder
FROM node:18 AS deps
WORKDIR /app
# Copy only the dependency manifest files
COPY package.json package-lock.json ./
# Docker caches this layer ONLY if manifest files change
RUN npm install

# Stage 2: Application build
FROM node:18 AS runner
WORKDIR /app
# Copy only the pre-installed dependencies from the first stage
COPY --from=deps /app/node_modules ./node_modules
# Copy source code last
COPY . .
RUN npm run build

Why This Works

By copying only package.json and package-lock.json first, the RUN npm install layer remains cached as long as your dependencies don't change. When you modify your application logic, Docker sees that package.json is identical, reuses the cached node_modules layer, and only re-runs the final COPY and RUN commands.

This ordering transforms your build process from a time-consuming full-reinstall into a rapid incremental update. By ensuring that "heavy" layers appear early in the build sequence and remain isolated from your "live" code, you effectively minimize redundant network and CPU usage during every iteration.

Key Takeaway: Always order your build instructions to copy dependency manifests and install packages before copying your frequently changing source code to maximize cache hits.