Knowing how to rebuild a Docker image the right way comes down to understanding what Docker's build cache actually invalidates, and what it doesn't — because a plain docker build after a base image update or a dependency patch can silently reuse a cached layer that never picks up the fix you were expecting. A docker rebuild that "succeeds" without pulling the intended change is one of the more common reasons a patched CVE turns up again in a production scan weeks later. Before assuming a rebuild fixed anything, it's worth being able to list images in a docker registry and check which digest a given tag actually resolves to right now.
What actually happens during a Docker rebuild?
Docker builds an image layer by layer, and each instruction in the Dockerfile produces a layer that's cached based on the instruction and its inputs. If nothing about a layer's inputs changed — the exact command, the exact files it copies, the exact base image tag — Docker reuses the cached layer instead of re-executing it. That's the whole point of layer caching: fast, incremental rebuilds. The catch is that "nothing changed" is evaluated narrowly. A FROM node:20 line doesn't automatically re-pull a newer node:20 tag just because time passed and the upstream image was patched; Docker treats the tag reference itself, not the digest it currently resolves to, as the cache key unless you force otherwise.
When does a docker rebuild silently skip a fix you need?
Two situations cause this most often. First, base image drift: your Dockerfile pins a mutable tag like node:20-slim, the upstream maintainers patch a vulnerability and re-push that tag, but your local Docker daemon still has the old image cached under that tag name and won't re-pull it without an explicit instruction. Second, dependency layer caching: if your Dockerfile copies package.json and runs npm install in one layer, then copies the rest of the source in a later layer, a change to source code alone won't invalidate the install layer — which is usually what you want for build speed, but means a patched transitive dependency introduced only through a fresh lockfile resolution won't get picked up unless the lockfile itself changed.
How do you force a docker rebuild to actually pull fresh layers?
docker build --no-cache rebuilds every layer from scratch, ignoring the cache entirely — reliable but slow, and overkill for most day-to-day rebuilds. docker build --pull is the more surgical fix for base image drift specifically: it forces Docker to check the registry for a newer digest behind the tag before starting the build, rather than trusting whatever's cached locally. For CI pipelines, the more robust pattern is pinning base images by digest (FROM node@sha256:...) rather than by mutable tag, and updating that digest deliberately through a dependency-bump PR — which makes base image updates visible in version control instead of happening invisibly whenever someone rebuilds.
What should trigger a rebuild automatically, rather than waiting for someone to remember?
Three triggers are worth wiring into CI regardless of whether application code changed: a new CVE disclosed against the current base image, a scheduled rebuild cadence (weekly is common) that forces a --pull rebuild to catch upstream security patches, and a lockfile change from a dependency update PR. Scanning the resulting image after every rebuild — not just at release time — is what actually closes the loop; a rebuild that doesn't get re-scanned just produces a fresh image with the same unverified assumption about what's inside it. Safeguard's SCA product can scan container images as part of that pipeline step, flagging newly introduced or newly disclosed vulnerabilities in the base image and dependency layers before the rebuilt image ships.
Does rebuilding always mean starting from a clean cache?
No — and treating every rebuild as a full --no-cache run is its own problem, since it slows down every CI run for a benefit you only need when base images or lockfiles have actually changed. The better default is layer ordering that makes the cache work for you: put instructions that change rarely (installing system packages, setting up the runtime) early in the Dockerfile, and instructions that change on every commit (copying application source) as late as possible. Combined with --pull on a schedule and digest pinning for reproducibility, this gets fast day-to-day rebuilds without the silent staleness problem.
FAQ
How do I force Docker to rebuild without using the cache at all?
Run docker build --no-cache -t your-image . — this ignores every cached layer and rebuilds from the first instruction, which is useful for confirming a build is reproducible or ruling out cache-related staleness when debugging.
Does docker rebuild automatically update the base image?
No, not unless you pass --pull, which forces Docker to check the registry for a newer image behind the tag before building — without it, a locally cached base image under the same tag name will be reused even if the upstream tag has been repointed to a patched version.
What's the difference between docker build and docker rebuild?
There's no separate docker rebuild command — "rebuilding" just means running docker build again, and the cache behavior described above determines whether that rebuild actually re-executes anything or reuses previous layers wholesale.
Should CI pin base images by tag or by digest?
Digest pinning (FROM node@sha256:...) gives fully reproducible builds and makes base image changes an explicit, reviewable commit; tag pinning (FROM node:20-slim) is more convenient but means the same Dockerfile can silently build a different image on different days as the tag's underlying digest changes upstream.
How do I check what's actually in a docker registry before rebuilding?
Use your registry's API or CLI (docker manifest inspect, or a registry-specific listing command) to pull the current digest behind a tag. Running a docker registry list images check against the repository you depend on tells you whether the upstream maintainers have actually re-pushed a patched image since your last pull.