The Build Is Slow, So Let's Just Add --no-cache to CI?
Scenario
Docker builds in CI have crept from 3 minutes to 11 over the past months. Worse, a recent release shipped with old dependencies even though the team was sure they had been updated — a stale-cache incident that burned everyone's trust in the build. The Dockerfile copies the whole working directory before installing dependencies, and the base image is referenced by a floating tag rather than a pinned digest.
The Quick Fix on the Table
A colleague proposes adding --no-cache to every CI build. No cache means no stale layers, no "is it the cache?" debugging sessions, and every image guaranteed fresh. One flag, and the whole class of problem disappears.
The quick fix is on the table and the room is waiting for your call. Would you sign off on it? Take a position and justify it — out loud or on paper — before revealing the analysis.
Why the Quick Fix Fails
- It makes the slow-build problem permanent. The 11-minute build exists because cache hits are already poor;
--no-cacheguarantees the worst case on every single push — dependencies reinstalled from scratch even when nothing changed. - It punishes the wrong component. The cache did exactly what the Dockerfile told it to. Copying all sources before installing dependencies and floating base tags are configuration bugs; discarding the cache is blaming the tool for the instructions.
- It doesn't even fix the staleness. A floating base tag means the registry decides what "latest" is; lockfile-less installs mean the package index decides versions at build time.
--no-cachemakes builds fresh, not reproducible — two different builds of the same commit can still differ. - Costs multiply quietly. Full rebuilds on every push mean more CI minutes, more registry bandwidth, more load on package mirrors — a recurring tax paid on every commit forever to avoid a one-day Dockerfile fix.
- Feedback gets slower right when it matters. Hotfixes and incident rollforwards wait behind the same full rebuild as everything else.
The interviewer nods: “Fine, the quick fix is off the table. So what exactly would you do — step by step?” Sketch your plan before revealing the approach.
The Right Approach
- Reorder the Dockerfile for correct invalidation. Copy only the dependency manifests first, install, then copy the source:
COPY package*.json ./→RUN npm ci→COPY . .. Now code changes reuse the dependency layer, and dependency changes — the manifest changing — correctly bust it. - Pin the base image by digest. Reference
node:20-slim@sha256:…instead of a floating tag, so the base can only change through an explicit, reviewed commit — that is the actual cure for "we shipped something other than we thought". - Install from lockfiles.
npm ci/pip install -r requirements.txtwith committed lockfiles makes dependency versions a function of the repository, not of the build day. - Give CI a reliable shared cache. Ephemeral runners lose local cache between jobs; use BuildKit's registry-backed cache (
--cache-from/--cache-to type=registry) so every runner starts warm. - Verify the fix with the failure that started this. Bump a dependency in the manifest and confirm the build reinstalls it; change only source code and confirm the dependency layer is reused. Both behaviors, demonstrated, rebuild the team's trust.
- Keep a scheduled clean build as a canary. A nightly or weekly
--no-cachebuild catches genuine cache corruption and upstream drift — using the flag as a periodic audit instead of a per-push penalty.
Final pushback: “Your plan costs more time and money than the quick fix. Convince me.” How do you defend your position under pressure?
How to Defend It
- "--no-cache turns every build into our worst-case build. We'd be institutionalizing the 11 minutes we're complaining about."
- "The stale-dependency release wasn't the cache misbehaving — it was our Dockerfile telling the cache that copying source doesn't affect dependencies. Fix the instruction, not the mechanism."
- "Fresh isn't the same as reproducible. With a floating base tag, --no-cache builds can still differ between Monday and Tuesday; a pinned digest and lockfiles are what make builds deterministic."
- "The reorder is a two-line diff and typically takes builds from 11 minutes back to 2 or 3 for code-only changes — better than --no-cache on both speed and correctness."
- "I'll happily keep --no-cache as a nightly canary build. That gives us the 'guaranteed fresh' audit without charging every developer for it on every push."