Every engineering team has a CI pipeline that takes too long. The team has known about it for months. Engineers wait for it. Pull requests sit unmerged for hours because the pipeline is queued. The cost of the wait is paid in small interruptions and lost focus, every day, by every engineer on the team. The team's standing complaint at every retro is some version of "CI is slow."
The slow CI tends to be the same slow CI it was two years ago. The team's response, when asked, is that they will get around to optimizing it. They have not. The work to actually fix it, when somebody finally does it, is rarely the work the team expected.
This is the operator view of where time hides on a typical CI pipeline that has not been profiled seriously in a while.
Most of the time is in setup, not in work
The largest source of CI slowness in 2026 is rarely the actual computation the pipeline performs. It is the work the pipeline does before and after the actual computation. The repeated work of provisioning a runner, pulling a base image, installing dependencies, restoring caches, and tearing down the environment.
For a typical pipeline that takes twenty minutes end to end, the actual tests, lints, and build steps are running for somewhere between four and eight minutes. The other twelve to sixteen minutes are setup and teardown. The team that spends a week optimizing the setup and teardown commonly cuts the pipeline duration in half without touching a single test.
The specific places this hides are predictable. Dependency installation that pulls from upstream registries with no local cache hits, or cache hits that take longer to restore than they save. Container image pulls that re-download a multi-gigabyte base image every run. Test setup that performs database migrations from scratch instead of reusing a snapshot. Cleanup steps that wait on slow shutdown handlers.
A profiling pass on the pipeline, where each step is timed and the timing is presented as a flame graph or a sorted list, is usually enough to identify the largest offenders. The team that actually does this pass tends to find that the longest step is something nobody had thought about, often a step that runs at the start and is so familiar that it had become invisible.
Tests are not always the bottleneck
The instinct, when looking at a slow pipeline, is to look at the tests. The tests are usually visible, well understood, and easy to point at. They are also frequently not the largest opportunity.
A useful first move is to look at the longest five steps in the pipeline, regardless of what they are. If the longest steps are tests, parallelize them. If the longest steps are dependency installation, fix the cache. If the longest steps are integration tests with a database, fix the fixture loading. The fix follows the actual bottleneck, not the assumed one.
When tests are the bottleneck, the first question is whether they need to be running in this pipeline at all. Many teams run their full suite on every commit because the team's habit is to run everything. A more honest pipeline runs unit tests on every commit and integration tests on a smaller cadence, perhaps on merge to main rather than on every push to a branch. The behavioral change is harder than the technical change, but the time savings are large.
Caching is harder than it looks
Most CI pipelines have caching. Most CI pipelines have caching that does not work as well as it should.
The common failures are subtle. The cache key is too coarse, so changes that should not invalidate the cache do. The cache key is too fine, so changes that should hit the cache miss it. The cache restoration takes longer than the work it skips, because the cache is too large and the network to the cache is too slow. The cache lives in a region that is not local to the runners, adding latency to every restore.
The fix for each of these is specific. The diagnostic is the same. Time the restore step. Time the work it is supposed to skip. If the restore is taking more than half as long as the work, the cache is not paying for itself. Either the cache strategy is wrong, the cache infrastructure is wrong, or the work is fast enough not to need a cache at all.
Several teams who have profiled this end up disabling caching for some steps, because the unstable cache was producing more variance and frustration than skipping the cache and doing the work fresh. That is a legitimate outcome and not a failure.
Parallelism is often free
If the pipeline is sequential, the question of whether it could be parallel is worth the hour to think through. Tests can run in parallel across many runners. Build steps that produce independent artifacts can run on different runners. Lints and type checks can run alongside tests rather than before them.
Most CI tools support this directly. The work is mostly in the configuration. Teams that have not done this in a while can usually cut their pipeline duration significantly with a few hours of pipeline reorganization.
The trap to avoid is parallelism that produces nondeterministic ordering for steps that depend on shared state. Tests that pass in serial and fail in parallel are a sign of order-dependence that is itself a real bug, even if the team's instinct is to run the tests in serial to make the failure go away.
Long-tail steps are sometimes load-bearing
The pipeline that takes twenty-five minutes today often has one step that takes ten of those minutes. The team's instinct is to optimize that step. Sometimes the right call. Sometimes not.
A long step is sometimes load-bearing. The full integration test suite that takes ten minutes is producing real value, and shortening it by skipping cases means losing real coverage. Replacing it with a faster but less thorough version is a regression, not an optimization.
The honest framing is to ask what the step is preventing. If the step exists to catch a class of bug that has been caught zero times in the last year, the step has stopped paying for itself and can be retired. If the step has caught a real bug in the last quarter, optimizing it without losing what it catches is the work, not removing it.
Where this work pays off
A typical engineering team running a typical pipeline can usually cut their CI duration by thirty to sixty percent in a focused two-week project, without changing the test coverage or the behavior the pipeline enforces. The wins are concentrated in setup and teardown work, in cache fixes, and in parallelism that should have been on the whole time.
The cost of not doing this is paid every day in lost engineer focus. A team of fifteen engineers waiting an extra ten minutes on each push is paying many hours per week in waste. Over a year, the math is uncomfortable.
The work to fix this is finite. The savings compound, because the next year of work happens against the faster pipeline. The teams that do the work usually wonder why they did not do it sooner. The teams that have not done it yet are paying for the answer one slow run at a time.