For a long time, our build pipeline felt like weather: an unavoidable force that arrived every morning and made everyone wait. A clean build took almost twenty minutes, and the usual advice was to buy faster machines or rewrite the stack.
We did neither. Instead, we treated the build as a product in its own right: something with users, sharp edges, and a trail of evidence if we were willing to look for it.
Start by measuring, not guessing
The first useful change was also the least glamorous. We added timing around every stage of the pipeline and collected it for a week. The results made a few comfortable assumptions impossible to maintain.
“The slowest part of a build is rarely the part everybody is talking about.”
Compilation was not our main problem. Repeated dependency work, an overly broad cache key, and a handful of serial tasks were quietly consuming most of the clock. Once that was visible, the path forward was much less dramatic—and much more effective.
We tightened the inputs to our cache, moved independent work into parallel steps, and made the expensive checks run only when the files they protected had changed. No new framework. No migration. Just a build that finally did less unnecessary work.