Docker path · Building images · Topic 4 of 12

Dockerfiles that build fast

Not started

Docker caches every build step. Before running an instruction it checks whether it has already built that exact step on top of that exact parent; if so it reuses the stored layer and moves on. Fast Dockerfiles are written so that the slow steps (installing dependencies) sit above the parts that change often (your code), and so that only the files a step really needs can affect it.

Why it matters: A well-ordered Dockerfile rebuilds in a second after a code change; a badly ordered one reinstalls every dependency on every commit, locally and in CI.

  1. 1Each step has a cache key

    A step is reused if its instruction and inputs are unchanged. For COPY the inputs are the files' contents; for RUN it is only the command text.

  2. 2A miss invalidates everything below

    Once one step has to rerun, every later step reruns too, even if it did not change.

  3. 3Stable things first

    Base image, system packages, then the dependency manifest and install, and only then your source code.

  4. 4A small build context

    .dockerignore keeps node_modules, .git, secrets and build output out of the context, so they neither slow the build nor bust the cache.

1

How it works

The explanation, with examples you can run.

How the cache decides

  • FROM is keyed by the base image digest.
  • COPY and ADD are keyed by a checksum of the copied files' contents and metadata. Changing a file that is copied invalidates the step; modification times alone do not.
  • RUN is keyed by the command text only. Docker does not know that apt-get update would return something different today.
  • When one step misses, every step after it is rebuilt.

An ordering that caches well

FROM node:22-alpineWORKDIR /app# 1. Only the dependency manifests: this layer changes when dependencies changeCOPY package.json package-lock.json ./RUN npm ci --omit=dev# 2. The source code: changes on every commit, so it comes lastCOPY . .USER nodeEXPOSE 3000CMD ["node", "server.js"]

After editing server.js, a rebuild reuses everything up to the final COPY:

docker build --progress=plain -t hello:1 .# #6 [3/5] COPY package.json package-lock.json ./# #6 CACHED# #8 [4/5] RUN npm ci --omit=dev# #8 CACHED# #9 [5/5] COPY . .# #9 DONE 0.0s

With COPY . . placed before npm ci, the same one-line edit shows RUN npm ci running again (added 1 package ... in 439ms here, minutes in a real project).

Keep the context small

docker build . sends the directory (the build context) to the builder. Anything in it can be copied, and anything copied can change a cache key. A .dockerignore next to the Dockerfile keeps it lean:

node_modules.git*.log.envDockerfile.dockerignore

Without it, COPY . . would copy your local node_modules (built for macOS, perhaps) over the ones just installed, any edit under .git would bust the cache, and .env would end up inside the image for anyone who pulls it.

Habits that help

  • Combine apt-get update and apt-get install in one RUN, so the package list is never older than the install, and clean the package cache in the same step.
  • Pin the base image (node:22-alpine, or better a digest) rather than latest, so the first layer does not change under you.
  • Use the lockfile and the clean-install command (npm ci, pip install -r with hashes, go mod download), so the install step is reproducible.
  • Copy only what a step needs. A tool that only needs go.mod should not see the whole tree.
  • In CI, where every runner starts empty, export the cache to the registry or the CI cache (--cache-to / --cache-from), or every build starts from zero.
2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.You edit one line in server.js and rebuild. Which steps run again?
    FROM node:22-alpineWORKDIR /appCOPY . .RUN npm ci --omit=devCMD ["node", "server.js"]
  2. 2.RUN apt-get update && apt-get install -y curl was cached three months ago. What does a rebuild do?
  3. 3.What is the main job of .dockerignore?

0 of 3 right so far. Get all three to finish this topic.