Waiting compounds.
A build delay is multiplied by every engineer, every context switch, and every change that needs verification. When feedback arrives after attention has moved elsewhere, the cost is larger than the elapsed minutes: interrupted reasoning, larger change batches, fewer experiments, and slower review.
Fast clean builds are useful for CI and onboarding, but most development happens through incremental edits. A team can improve the headline clean-build number while leaving its everyday inner loop untouched.
The unit of performance is a workflow.
Define the edit, machine state, target, configuration, and expected result. Then compare like with like.
Warning signs in an unhealthy build.
Incremental resembles clean
A small edit repeatedly recompiles broad parts of the graph.
No-op work remains
Running the same build twice still executes scripts, generators, or compilation.
The machine looks idle
One serialized action controls the critical path while available CPU goes unused.
Scripts are opaque
Unspecified inputs or outputs make every script run and prevent safe caching.
Local and CI disagree
Different environments, flags, or dependency states produce different work.
Cold state dominates
Branch switching, dependency resolution, or indexing routinely destroys the fast path.
Measure the shape, not one average.
Begin with a small benchmark suite: clean, representative incremental edits, no-op, and a cold-start workflow where it matters. Capture enough samples to distinguish signal from machine noise and report distributions rather than a single best run.
p50 and p90 elapsed time
Typical experience and the long tail engineers remember.
Critical path and invalidation
Which actions govern completion and how far each edit propagates.
Cache hit quality
Hits by action class, download cost, misses, and why keys change.
Time to first useful error
How quickly an engineer learns that the change needs correction.
Concurrency and utilization
Whether work is parallel, serialized, I/O-bound, or starved.
Monthly wait cost
Frequency × affected engineers × delay, with conservative assumptions.
Improve the constraint that governs completion.
Compiler and type-checking work
Find expensive source units, pathological expressions, avoidable whole-module work, and toolchain settings that change compilation behavior.
Dependency boundaries and invalidation
Reduce high-fan-out dependencies, unstable interfaces, bridging surfaces, and module edges that make small changes broad.
Scripts and code generation
Declare precise inputs and outputs, eliminate unconditional work, make generators deterministic, and move work off the critical path.
Linking, packaging, and resources
Profile post-compilation actions instead of assuming the compiler owns the whole delay.
Local and remote reuse
Improve cacheability before adding cache capacity. Measure hit rate, transfer cost, key stability, and the actions worth reusing.
IDE, indexing, and setup
Treat indexing, dependency resolution, generated project state, and first-day setup as part of the developer workflow.
What a build-performance engagement produces.
We agree on representative workflows, capture the build graph and traces, classify lost time, and rank interventions by expected value and risk. A focused engagement typically ends with a reproducible benchmark, evidence-backed findings, implemented quick wins where appropriate, and a prioritized plan for larger changes.
The final step is regression control: repeatable measurements, ownership, and thresholds that make a slowdown visible before it becomes the new normal.
Platform references.
For Apple-platform projects, Apple documents both build-efficient coding practices and Xcode compilation caching. These are useful inputs, but the correct intervention still depends on the measured project graph and workflow.