DevTools•Jun 2026•3 min read

Clean Build vs Partial Build

A clean build wipes all artifacts and compiles from scratch; a partial build reuses cached outputs and only recompiles what changed. Speed versus certainty. We pick the one that doesn't lie to you.

The short answer

Partial Build over Clean Build for most cases. Partial builds win because correctness is a tooling problem, not a virtue you earn by burning CPU.

  • Pick Clean Build if cutting a release, debugging a Heisenbug you suspect is stale-cache contamination, or your build system has no trustworthy dependency graph
  • Pick Partial Build if in any normal edit-compile-test loop — which is 95% of your day — and your toolchain tracks dependencies correctly
  • Also consider: The real choice isn't clean vs partial. It's whether your build graph is correct. Fix the graph and partial builds become safe; leave it broken and even clean builds can't save you.

— Nice Pick, opinionated tool recommendations

What they actually are

A clean build deletes every prior artifact — object files, caches, generated code — and rebuilds the world from source. A partial (incremental) build consults a dependency graph, fingerprints inputs, and rebuilds only the nodes whose inputs changed, reusing everything else. Clean is make clean && make, rm -rf node_modules dist, gradle clean build, a fresh CI runner with a cold cache. Partial is plain make, tsc --incremental, Turborepo cache hits, Bazel pulling from a remote action cache. The difference is trust: a partial build trusts its tooling to know what changed, a clean build trusts nothing and pays for that paranoia in wall-clock time. One is an optimization, the other is a reset button. Most teams treat the reset button as a safety blanket, which is exactly the habit worth interrogating.

Speed and the cost of paranoia

This is not close. A clean build of a mid-sized monorepo can take 15-40 minutes; the partial rebuild after a one-line change is often under 10 seconds. Multiply that gap by every commit, every CI run, every developer, every day. Teams that clean-build on every CI push are setting money on fire and calling it discipline. Remote caching (Bazel RBE, Turborepo Remote Cache, sccache, Gradle build cache) pushes the common case toward instant — a cache hit returns the prebuilt artifact across machines, so even a 'cold' CI runner skips work someone already did. The clean build throws all of that away on purpose. If your feedback loop is slow, your engineers context-switch, ship less, and stop running tests locally. Slow builds are a culture problem disguised as a config choice.

Correctness and reproducibility

Here's the clean build's one honest argument: it's reproducible by brute force. No stale headers, no orphaned object file from a renamed source, no cache poisoned by a non-hermetic step reading the system clock or an env var. When a partial build produces a binary that a clean build can't — the classic 'works on my machine' — you've found a bug in your dependency graph, not a reason to clean forever. That's the tell. Clean builds don't make your build correct; they paper over an incorrect build by never reusing state. Bazel's whole thesis is that hermeticity makes incremental builds bit-identical to clean ones, which means the speed/correctness tradeoff is false when your tooling is good. If you genuinely can't trust a partial build, the problem is upstream of this decision.

When to actually reach for clean

Don't romanticize it, but don't ban it either. Clean-build your release artifacts — the binary that ships should not depend on six weeks of accreted local cache state nobody can reproduce. Clean when you've changed compiler version, toolchain flags, or a build-system config that your incremental layer doesn't fingerprint (many don't track their own settings). Clean when you're chasing a bug that smells like stale state: phantom symbols, a test passing locally and failing in CI, output that doesn't match source. And clean periodically in CI as a canary — a nightly clean build catches dependency-graph rot before it bites a release. Outside those cases, reaching for clean is a confession that you don't trust your tools. Fix the trust, not the symptom. The partial build is home; the clean build is the fire extinguisher, not the front door.

Quick Comparison

FactorClean BuildPartial Build
Speed (typical rebuild)Minutes to tens of minutes — rebuilds the entire graphSeconds on a small change; instant on a cache hit
ReproducibilityBrute-force reproducible; immune to stale stateReproducible only if the dependency graph is hermetic
Release artifactsIdeal — no accreted local cache state in the shipped binaryRisky if non-hermetic steps leaked into the cache
Daily dev feedback loopPunishing; kills iteration and local test runsFast; keeps engineers in flow
CI cost at scaleExpensive — burns compute on work already doneCheap with remote caching; reuses cross-machine artifacts

The Verdict

Use Clean Build if: You're cutting a release, debugging a Heisenbug you suspect is stale-cache contamination, or your build system has no trustworthy dependency graph.

Use Partial Build if: You're in any normal edit-compile-test loop — which is 95% of your day — and your toolchain tracks dependencies correctly.

Consider: The real choice isn't clean vs partial. It's whether your build graph is correct. Fix the graph and partial builds become safe; leave it broken and even clean builds can't save you.

Clean Build vs Partial Build: FAQ

Is Clean Build or Partial Build better?

Partial Build is the Nice Pick. Partial builds win because correctness is a tooling problem, not a virtue you earn by burning CPU. A good build graph (Bazel, Turborepo, Gradle, sccache) gives you both speed and reproducibility. Clean builds are what you reach for when you don't trust your tools — and that distrust is the actual bug. Reserve the clean build for release artifacts and the rare incremental-state corruption. Live in the partial build.

When should you use Clean Build?

You're cutting a release, debugging a Heisenbug you suspect is stale-cache contamination, or your build system has no trustworthy dependency graph.

When should you use Partial Build?

You're in any normal edit-compile-test loop — which is 95% of your day — and your toolchain tracks dependencies correctly.

What's the main difference between Clean Build and Partial Build?

A clean build wipes all artifacts and compiles from scratch; a partial build reuses cached outputs and only recompiles what changed. Speed versus certainty. We pick the one that doesn't lie to you.

How do Clean Build and Partial Build compare on speed (typical rebuild)?

Clean Build: Minutes to tens of minutes — rebuilds the entire graph. Partial Build: Seconds on a small change; instant on a cache hit. Partial Build wins here.

Are there alternatives to consider beyond Clean Build and Partial Build?

The real choice isn't clean vs partial. It's whether your build graph is correct. Fix the graph and partial builds become safe; leave it broken and even clean builds can't save you.

🧊
The Bottom Line
Partial Build wins

Partial builds win because correctness is a tooling problem, not a virtue you earn by burning CPU. A good build graph (Bazel, Turborepo, Gradle, sccache) gives you both speed and reproducibility. Clean builds are what you reach for when you don't trust your tools — and that distrust is the actual bug. Reserve the clean build for release artifacts and the rare incremental-state corruption. Live in the partial build.

Related Comparisons

Disagree? nice@nicepick.dev