Lesson 2 of 30
Every Dockerfile instruction is a layer, every layer is cached, and cache invalidation cascades downward — one line in the wrong order can silently turn a 3-second rebuild into a 3-minute one.
14 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A Dockerfile has 5 instructions. On a rebuild, instruction 3's cache is invalidated because its input changed. What happens to instructions 4 and 5?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Each instruction in a Dockerfile (FROM, RUN, COPY, etc.) produces one layer — a diff against the layer before it. Docker caches every layer by hashing its instruction plus its inputs; on a rebuild, it walks the Dockerfile top to bottom and reuses cached layers until it hits the first one whose hash has changed. Every layer after that point rebuilds from scratch, even if nothing in them actually changed — cache invalidation cascades downward, never sideways.
That single rule explains almost every real Dockerfile performance decision:
FROM node:20-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./ # 1. changes rarely
RUN pnpm install --frozen-lockfile # 2. slow — worth protecting from cache invalidation
COPY . . # 3. changes constantly
RUN pnpm build # 4. must rerun whenever source changes anyway
Because the lockfile is copied before the full source tree, editing a single component file only invalidates layers 3 and 4 — the slow pnpm install in layer 2 stays cached. Reverse the order (copy everything, then install) and every source change reruns the full install.
Each instruction is one cached layer, stacked on the layer before it.
A few instructions look interchangeable and aren't:
RUN vs CMD vs ENTRYPOINT — RUN executes at build time and produces a layer; CMD/ENTRYPOINT only define what runs when a container starts, and produce no filesystem change at all.COPY vs ADD — COPY does exactly what it says; ADD also auto-extracts local tar archives and can fetch remote URLs — extra, rarely-needed behavior that's a common source of surprise. Most style guides recommend COPY unless you specifically need ADD's extra behavior.ARG vs ENV — ARG exists only during the build (e.g. --build-arg NODE_ENV=production) and isn't present in the final running container unless explicitly promoted to ENV; ENV persists into every container started from the image.docker build . first packages everything in the current directory (minus .dockerignore entries) and ships it to the Docker daemon — a node_modules folder or a large .git history in that context slows down every single build, even ones that never touch those files.RUN instructions merge shell commands for cache efficiency, deliberately. RUN apt-get update && apt-get install -y curl in one line is standard practice specifically because each RUN is its own cached layer — splitting update and install into separate RUN lines can cache a stale apt-get update layer, silently installing outdated package versions later.ARG values are visible in the image's build history (docker history) even though they don't persist into the running container — ARG is not a safe place for secrets, despite feeling more "build-time private" than ENV."Our CI build takes 8 minutes and it used to take 90 seconds — how would you debug that?" is a real, common question, and the strong answer starts with layer ordering and cache invalidation, not a vague "optimize the Dockerfile." Naming the specific mechanism — which instruction busted the cache, and why everything after it reran — is the difference between diagnosing the problem and guessing at it.