Skip to content
Latchkey
Published June 2026 by Kaveh Alemi

The 2026 CI Cache Hit-Rate Benchmark

What dependency and build cache hit rates look like across ecosystems in 2026, and the minutes a hit actually saves.

64%
median dependency cache hit rate on a default ephemeral runner setup
Latchkey analysis (modeled)
3.1 min
median minutes saved per job on a warm dependency cache hit
Latchkey analysis (modeled)
70%
modeled managed-runner cost saving vs GitHub-hosted
Latchkey analysis (modeled)

Executive summary

Caching is the cheapest speedup in CI and the most inconsistently realized. A cache hit skips the dependency resolve, the download, and often the build step entirely, turning a multi-minute prologue into a sub-second restore. But on default ephemeral runners the cache frequently lives somewhere slow or gets evicted under storage pressure, so the hit rate sits well below what the same pipeline could reach with a fast, persistent cache layer. Teams celebrate having 'turned caching on' without ever measuring whether it actually hits.

This benchmark separates two things that are usually conflated: how often the cache actually hits across ecosystems, and how many minutes a hit is worth. Both matter independently. A 90 percent hit rate on a cache that only saves thirty seconds is worth less than a 70 percent hit rate on a cache that saves five minutes. We model hit rates for dependency and build caches per ecosystem, convert each hit into recovered wall-clock minutes, and price those minutes against published runner rates so the saving is expressed in both time and money.

The ecosystem you build in sets a natural ceiling. Lockfile-keyed ecosystems with stable module graphs, Go modules and Cargo in particular, cache cleanly and hit often, because the cache key maps deterministically to a content-addressed set of dependencies. Churnier dependency trees and looser keys hit less reliably. Knowing your ecosystem baseline tells you how much headroom exists before you touch any configuration, and whether the problem is your keys or your backend.

The backend then decides whether you reach that ceiling. A correctly keyed cache still underperforms badly if its storage is slow to restore or evicts entries aggressively. Moving from the default action cache to a fast managed warm cache lifts the modeled hit rate from the mid-sixties into the low-nineties, because entries survive across otherwise ephemeral jobs and restore fast enough to be worth using on every run. A managed runner keeps that cache warm in front of jobs that would otherwise throw it away with the instance.

The payoff compounds because the prologue runs on every single job. Unlike a one-time optimization, a cache hit pays out on every push, every branch, every matrix leg, for as long as the pipeline exists. That makes the cache hit rate one of the highest-leverage numbers in CI: a few points of improvement, multiplied across thousands of jobs a week, is a large and recurring saving in both engineer wait time and runner spend.

Dependency cache hit rate by ecosystem
Node (npm)79%Python (pip)72%Rust (cargo)86%Java (maven)81%Go (modules)90%

Modeled median hit rate on a managed persistent cache across common ecosystems. · Source: Latchkey analysis (modeled)

Minutes saved per job on a cache hit
Dependency cache3.1 minBuild cache4.6 minDocker layer cache5.2 minCombined (managed)8.9 min

Modeled wall-clock minutes recovered when the cache hits, by cache type. · Source: Latchkey analysis (modeled)

Email me the report

The full report is right here on this page, free. Want the link in your inbox to read later or share, plus new Latchkey reports as they drop? Drop your email and we will send it over.

Sent! Check your inbox for the report link.

No spam. Unsubscribe anytime.

Hit rate varies widely by ecosystem

Lockfile-keyed ecosystems with stable module graphs cache cleanly and hit often, while ecosystems with churnier dependency trees hit less reliably. Go modules and Cargo sit near the top of the benchmark because their cache keys map deterministically to a content-addressed dependency set: the same lockfile always restores the same bytes, so the key is precise and the hit is predictable.

Node and Python sit lower not because the tooling is worse but because their dependency graphs churn more and their cache keys are easier to get wrong. A key scoped too loosely serves stale content and a key scoped too tightly almost never matches, and both failure modes are more common in ecosystems where transitive dependencies shift frequently between runs.

Knowing your ecosystem baseline tells you how much headroom a faster cache can recover before you tune anything. A Go team already near 90 percent has little to gain from a better backend and should look at build caches instead; a Node team in the mid-seventies has real room to improve both the key and the storage. The chart sets that per-ecosystem expectation so a team can tell whether it is underperforming its ecosystem or simply hitting its natural ceiling.

  • Go modules and Cargo cache most cleanly because lockfile keys map to a content-addressed dependency set.
  • Node and Python hit less reliably because dependency graphs churn and keys are easier to misscope.
  • Compare your hit rate to your ecosystem baseline, not to a global average, to know if you have headroom.

The cache backend sets the ceiling on hit rate

A correctly keyed cache still underperforms if its storage is slow or evicts aggressively. The default action cache works, but it carries size limits and eviction policies that quietly drop entries under pressure, and on a busy repository the cache you saved this morning may be gone by afternoon. A key that would have hit finds nothing to restore, and the job pays the full cold install.

Moving from the default action cache to a fast managed warm cache lifts the modeled hit rate from the mid-sixties to the low-nineties. The difference is not the key, which is identical, it is that entries survive across ephemeral jobs and restore fast enough to be worth using every time. A self-managed bucket sits in between: it removes some eviction pressure but adds restore latency and operational burden that the team now owns.

The lesson is that hit rate is a property of the whole cache system, not just the key. Teams that tune their keys obsessively while leaving the cache on slow, evicting storage are optimizing the wrong half of the problem. The backend sets the ceiling; the key decides how close to that ceiling you get. A managed warm cache raises the ceiling without the team having to operate storage at all.

Cache hit rate by storage setup
No cache configured0%Default action cache64%Self-managed bucket71%Managed warm cache92%

Modeled hit rate across common cache backends on ephemeral runners. · Source: Latchkey analysis (modeled)

A hit is worth more than people assume

A dependency cache hit alone recovers a few minutes per job in the model, around 3.1 minutes for a representative pipeline. That sounds modest until you remember it pays out on every job, on every push, indefinitely. The prologue is the most repeated work in CI, so saving it is the most repeated saving available.

Stacking caches multiplies the effect. A build cache that avoids recompiling unchanged code recovers more than the dependency cache alone, and a Docker layer cache that skips rebuilding unchanged image layers recovers more still. Combined on a managed runner, the modeled saving reaches close to nine minutes per job, because each cache removes a different slice of the cold prologue and they do not overlap.

Because these minutes recur, they dominate the cost math over time. A one-time pipeline rewrite saves once; a cache hit saves on the next ten thousand jobs. Of every optimization in CI, dependency and build caching has the best ratio of payoff to effort precisely because the payoff is multiplied by job count rather than paid out a single time.

Cached jobs spend their minutes on real work

Once a warm cache is in place, the dominant slice of a job is useful test and build work rather than install and restore overhead. In the model, a cached job spends 71 percent of its time on real work, with cache restore, residual install, and cache save splitting the remainder. That is the whole point of caching: you are paying runner minutes for the work that matters, not for re-downloading dependencies you already had.

The residual slices are instructive. A small amount of install always remains because not every dependency is cacheable and lockfiles do drift, and the cache save step costs a little on the runs that update the cache. These are not waste; they are the cost of keeping the cache fresh, and they are far smaller than the cold install they replace.

The shift in the time split is also why caching improves the developer experience, not just the bill. A job that spends most of its wall-clock on real test execution gives faster, more honest feedback than one that spends half its time on setup. The cache moves the pipeline from 'mostly getting ready' to 'mostly doing the work', which is exactly the shape a fast feedback loop needs.

Where a cached job spends its time
Useful test/build work 71%
Cache restore 12%
Residual install 10%
Cache save 7%

Modeled split of a job once a warm cache is in place. · Source: Latchkey analysis (modeled)

Ephemeral runners throw the cache away unless something persists it

The defining property of a secure CI runner is that it is ephemeral: a fresh, single-use environment per job that is destroyed when the job ends. That isolation is exactly what you want for security, but it is hostile to caching, because the cache the job built dies with the instance unless it is explicitly persisted somewhere external.

This is the tension at the heart of CI caching. The same ephemerality that prevents state from bleeding between jobs also prevents the cache from surviving between jobs, so every team has to bolt on external storage to get a hit rate above zero. How well that external storage performs is what separates a 64 percent hit rate from a 92 percent one.

A managed runner resolves the tension by keeping a warm, persistent cache layer in front of the ephemeral jobs. Each job still runs in a clean, isolated environment, so the security and reliability properties hold, but the cache lives outside the instance and restores into each job at start. The team gets per-job isolation and a high hit rate at the same time, instead of trading one for the other.

A cache nobody measures is a cache that silently stops working

Caching is conceptually simple and operationally finicky, which is why so many teams configure it once and never look again. A dependency upgrade changes the lockfile, a refactor moves the cache directory, a CI change alters the key, and the hit rate quietly collapses to near zero while the pipeline still 'has caching enabled'. Nobody notices until someone asks why builds got slow.

The teams that win treat the cache hit rate the way they treat test coverage: as a number they watch over time, with an alert when it regresses. A visible hit rate turns a silent failure into a caught regression, and it makes the cost of a loose or broken key obvious instead of invisible. You cannot defend a saving you cannot see.

Instrumentation also tells you when you have hit your ceiling. If the hit rate is high and stable, further key tuning is wasted effort and the next win is a build or Docker layer cache. If it is low and volatile, the key or the backend is the problem. Without the measurement, teams optimize blind and frequently spend effort on the half of the system that was already fine.

  • Treat cache hit rate as a monitored metric with a regression alert, like test coverage.
  • A lockfile change, a moved cache directory, or a key edit can silently drop the hit rate to near zero.
  • A high stable hit rate means the next win is a build or Docker layer cache, not more key tuning.

Caching is the highest-ROI lever before you touch any test

Of all the ways to speed up a pipeline, caching has the best ratio of payoff to effort because it requires no change to application code. You do not refactor a test, split a module, or rewrite a build; you key a cache correctly and put it on fast storage, and the saved minutes appear on the next run.

That makes caching the right first move on almost any slow pipeline. Before sharding tests, before buying bigger runners, before rewriting a build script, a team should confirm its cache actually hits, because the cache fix is cheaper and frequently larger than any of those. Teams that skip straight to bigger runners are paying more to recompute work they could have restored for free.

It is also the move with the least risk. A wrong cache key serves stale content in the worst case, which a content-addressed key prevents, whereas a test refactor or a build rewrite can introduce real bugs. Caching is high payoff, low effort, and low risk, which is a rare combination and the reason it tops the optimization order in this report.

Recommendations

Measure your hit rate before you tune anything

You cannot improve a number you do not watch. Instrument dependency and build cache hit rates and alert on regressions the way you alert on failing tests. A cache that silently stopped hitting after a lockfile change is the most common and most invisible cause of a slow pipeline.

Key caches to the lockfile and toolchain version, content-addressed

Scope cache keys to the exact lockfile and toolchain so the key maps deterministically to a content-addressed dependency set. This is why Go and Cargo hit cleanly; the same discipline lifts Node and Python toward their ceiling and eliminates both stale hits and perpetual misses.

Put the cache on fast, persistent storage, not the default action cache

The backend sets the ceiling on hit rate. Default action caches evict under pressure and restore slowly; a fast managed warm cache lifts the modeled hit rate from the mid-sixties into the low-nineties without changing a single key, because entries survive across ephemeral jobs.

Stack dependency, build, and Docker layer caches

Each cache removes a different slice of the cold prologue, so they compound rather than overlap. A dependency cache alone recovers a few minutes; stacking build and Docker layer caches on a managed runner recovers close to nine minutes per job in the model.

Use a managed runner to keep the cache warm across ephemeral jobs

Ephemeral, single-use runners give you per-job isolation but throw the cache away with the instance. A managed runner keeps a persistent cache layer in front of isolated jobs, so you get a high hit rate and clean isolation at once, and bills the remaining minutes at roughly 70% below GitHub-hosted rates.

Outlook

Through 2026 and into 2027, caching moves from an optional optimization to an assumed property of a serious pipeline. As repositories grow and matrices widen, the cold prologue becomes a larger and larger share of total CI spend, so the hit rate becomes one of the most consequential numbers an engineering org tracks. Teams that do not measure it will increasingly be paying to recompute work their peers restore for free.

The architectural trend is toward the runner layer owning the cache rather than each team bolting on external storage. A managed warm cache in front of ephemeral jobs resolves the long-standing tension between isolation and cache persistence, and as that pattern spreads it removes both the operational burden of running cache storage and the variance between teams that get it right and teams that do not. The hit rate ceiling rises for everyone on the platform.

For most teams the practical takeaway is that the cheapest large win in CI is already available and frequently left on the table. Measure the hit rate, key the cache precisely, put it on fast persistent storage, and stack the cache types. Doing that before reaching for bigger runners or rewriting tests captures the highest-ROI saving in the pipeline, repeated on every job, indefinitely.

Methodology

This benchmark models dependency and build cache hit rates across major ecosystems and cache backends, converts hits into recovered wall-clock minutes, and prices those minutes against published GitHub Actions runner rates (Linux 0.008 per minute, managed 0.0025). Hit rates, minutes saved, and the cached-job time split are Latchkey modeled estimates labeled as such; the managed cost saving of 70% is a modeled figure and per-minute pricing ties to published rates. Figures labeled "modeled" are illustrative estimates derived from public pricing and typical pipeline shapes, not a primary survey; figures attributed to a named source reflect that source. Pricing reflects published rates at time of writing and should be verified against current provider pricing.

Sources

More Latchkey reports

See what you would save with Latchkey managed runners and self-healing. Start free → 30-day trial · No credit card