skip to content

You need a container image build to genuinely re-fetch things rather than reuse cached layers — for example to pick up new upstream OS package versions. What options does the Docker CLI give you, and how do they differ from each other?

level: middleimportance: should knowfreq 55%

answer

  1. --no-cache = whole build, blunt
  2. --pull = re-resolve FROM tag to today's digest
  3. --no-cache-filter=<stage> = surgical, BuildKit only
  4. ARG CACHEBUST referenced in RUN = from here down
  5. builder prune = reclaim/reset cache storage

basics

~20 s

--no-cache ignores all cached layers for the build; --pull refreshes the base image referenced by FROM; --no-cache-filter <stage> busts only chosen stages. Changing a referenced build argument invalidates from that instruction down. Each has a different blast radius and cost.

solid answer

~50 s

Because `RUN` caching matches on the command string, a step that fetches from the network can be reused indefinitely. Options, from broadest to narrowest: - **`docker build --no-cache`** — nothing is reused; every instruction runs. Correct for scheduled base-image refreshes and for reproducing 'works only on a warm cache' bugs, but it is the slowest option and shouldn't be the CI default. - **`--pull`** — re-resolves the `FROM` tag against the registry so you get today's digest for `alpine:3.20`. Often combined as `--pull --no-cache` for a nightly rebuild. - **`--no-cache-filter=deps,builder`** (BuildKit/Buildx) — busts only named stages, keeping the rest cached. - **A cache-bust build argument**: `ARG CACHEBUST` referenced in a `RUN`, passed as `--build-arg CACHEBUST=$(date +%s)`. The argument expands into the command string, so that step and everything below it rebuild. Place it immediately above the step that must re-run. Also `docker builder prune` / `buildx prune` to reclaim or reset cache storage.

code

bash · 11 lines
bash
# force only one stage to rebuild
docker buildx build --no-cache-filter=deps -t app:dev .

# rebuild everything on today's base image (scheduled refresh)
docker build --pull --no-cache -t app:nightly .

# bust from a specific instruction downward
docker build --build-arg CACHEBUST=$(date +%s) -t app:dev .

# reclaim cache storage older than a week
docker buildx prune --filter until=168h

go deeper

for a junior

Know --no-cache and --pull and what each one refreshes; be able to say why a stale apt-get update layer is a problem.

for a middle

Add --no-cache-filter and the referenced-ARG bust, and explain the blast radius of each — whole build, stage, or from-here-down.

for a senior

Argue for fixing the Dockerfile (fused update+install, pinned versions, pinned digests, ADD --checksum) and reserve flags for scheduled refreshes; mention builder GC as another source of cold builds.

for a principal

Frame it as a patching policy: how often bases are rebuilt from scratch, how digests get bumped, and how you keep 'fast cached build' and 'provably current base' as two separate, scheduled guarantees.

## Why you need an escape hatch at all The builder decides cache hits from keys, not from reality. A `RUN` step is matched on its command text, so `RUN apt-get update && apt-get install -y openssl` will keep reusing a months-old layer as long as its string and its parent are unchanged — even after an upstream security release. Nothing about the Dockerfile changed, so nothing rebuilds. Similarly `FROM node:22` is a *mutable tag*: the tag may now point at a new digest, but a builder that already resolved it will happily continue using the old image. So you need explicit ways to say 'ignore what you remember'. ## `--no-cache` `docker build --no-cache -t app .` disables cache lookups for the whole build: every instruction executes. It is the blunt instrument. Good uses: a scheduled (nightly/weekly) rebuild that picks up OS patches; reproducing a bug that only appears on cold builds; verifying that the Dockerfile still works from scratch — a `RUN` that depends on a file deleted from the repo can survive for weeks on a warm cache and then fail for a new contributor. Bad use: as the CI default 'to be safe'. It converts every build into a worst-case build, multiplies registry egress and pipeline minutes, and hides the ordering problems you should be fixing. ## `--pull` `--pull` forces re-resolution of every `FROM` reference against the registry. Without it, a builder that already has `python:3.12` locally will not check whether the tag moved. With it, you rebuild on top of today's base — which is precisely how you pick up base-image CVE fixes. `--pull` and `--no-cache` are orthogonal and frequently paired: `docker build --pull --no-cache` for a scheduled refresh. Note that if you pin `FROM python:3.12@sha256:…` by digest, `--pull` cannot change what you build on — an intentional tradeoff between reproducibility and automatic patching, usually resolved by a bot that bumps the pinned digest. ## `--no-cache-filter` BuildKit adds `--no-cache-filter=<stage>[,<stage>]`, which disables the cache only for named build stages. In a multi-stage Dockerfile you can force the `deps` stage to re-resolve dependencies while the expensive `toolchain` stage stays cached. It is the surgical version of `--no-cache` and is well worth knowing — most candidates only know the blunt flag. ## Cache-busting build arguments Because a referenced `ARG` is expanded into the `RUN` command string, it participates in the cache key: ``` ARG CACHEBUST=0 RUN echo "$CACHEBUST" && git clone --depth 1 https://example.com/repo.git ``` Passing `--build-arg CACHEBUST=$(date +%s)` changes the string, so that step and everything below it rebuild while everything above stays cached. This is the standard trick for a `git clone` or a `curl` of a moving artifact — steps whose text is constant but whose result is not. Two cautions. First, **placement is everything**: put the `ARG` immediately above the step that must re-run, because everything below it also rebuilds. Second, a build argument that changes every build — a commit SHA consumed at the top of the file — is an accidental cache-bust that silently destroys build times. Same mechanism, opposite intent. ## Fixing the Dockerfile instead Often the right answer to 'how do I force a rebuild' is 'stop needing to'. Fuse `apt-get update` with its `install` so they invalidate as one unit. Pin versions (`curl=8.5.0-2`) so the desired change is expressed as a text change and the cache does the right thing automatically. Prefer `ADD --checksum=sha256:…` for remote artifacts so a moved artifact is a loud failure rather than a silent stale hit. Cache correctness is mostly a Dockerfile-design problem; flags are for the residue. ## Clearing storage `docker builder prune` (or `docker buildx prune`, with `--all` and `--filter until=168h`) deletes cached build records to reclaim disk. That is a storage operation rather than a per-build flag, but it is the other way builds 'lose' their cache — and on a shared or long-lived builder, an aggressive GC policy explains mysterious cold builds. ## The summary to say out loud `--no-cache` = everything, `--pull` = base images, `--no-cache-filter` = chosen stages, a referenced `ARG` = from this instruction down. Reach for the narrowest one that solves the problem, and prefer changing the Dockerfile so the cache invalidates honestly.

  • Your nightly job runs `--no-cache` but the image still ships an old OpenSSL from the base layer. Why?
    `--no-cache` only stops reuse of your own build steps; it does not re-resolve the `FROM` reference. If the builder already has that tag locally it keeps building on the stale base. Add `--pull` so the tag is re-resolved against the registry — or, if the base is pinned by digest, bump the pinned digest, since `--pull` cannot move a digest reference.
  • A team added `ARG BUILD_ID` at the top of the Dockerfile for a label. Builds got much slower. What happened?
    The build argument changes every run, and because it is consumed near the top, the instructions below it get new cache keys and the miss cascades through the whole stage — including the dependency install. Move the `ARG` and its `LABEL` to the bottom of the file so only trailing metadata layers rebuild.

saying these in an interview costs you the question

  • Assuming `--no-cache` also refreshes the base image (that is `--pull`)
  • Making `--no-cache` the standing CI default instead of fixing instruction ordering
  • Putting a timestamp or commit-SHA build argument at the top of the Dockerfile
  • Thinking `docker builder prune` is a per-build flag rather than storage GC
  • Believing a cache-bust ARG affects only the single instruction that references it

context