For a long time, our build pipeline slowed down so gradually that no single change seemed responsible. A few seconds appeared here, another minute there, until waiting became an accepted part of the work.
We had no appetite for a rewrite. The stack was stable, the team knew it well, and replacing it would have traded a measurable problem for months of uncertainty. So we looked for improvements inside the system we already had.
Start by measuring, not guessing
Our first step was to record every stage of a build from the moment a change was submitted to the moment an artifact was ready. We tracked queue time, dependency installation, compilation, tests, packaging, and upload separately.
The results challenged nearly every assumption we had. Compilation was not the main bottleneck. Most of the lost time sat between familiar tasks: repeated setup, work that could run in parallel, and caches that were technically present but rarely reused.
The breakthrough wasn’t a faster tool. It was finally seeing where the time was going.
Once those gaps were visible, the fixes were deliberately small. We reordered independent jobs, made cache keys more stable, and stopped rebuilding artifacts that had not changed. Each adjustment saved only a little on its own, but together they reduced the median build from twenty-two minutes to just under eleven.