Skip to content
Latchkey
Published June 2026 by Kaveh Alemi

The State of Rust CI 2026

The build-time tax: why Rust pipelines are slow, how layered caching and sccache claw the minutes back, and where the runner layer decides the bill.

76%
of professional developers use CI/CD in their workflow
Stack Overflow Developer Survey
63%
of a cold Rust CI minute spent compiling, not testing
Latchkey analysis (modeled)
4.1x
faster clean CI build with a warm sccache plus target cache
Latchkey analysis (modeled)

Executive summary

Rust trades runtime speed and memory safety for compile time, and nowhere does that bill land harder than in CI. A clean build of a moderately sized workspace can take many minutes before a single test runs, and unlike most languages the compile step, not the test step, is the dominant line item on the invoice. For Rust teams, CI cost optimization is almost entirely a compile-caching problem, which inverts the usual advice to start with the test suite.

The reason compilation is so expensive is the same reason Rust programs are fast and safe at runtime. The compiler does aggressive monomorphization, exhaustive borrow checking, and heavy optimization, and it does all of it again from scratch every time a cold runner starts with an empty target directory. The work is real and unavoidable on a true cold build; the waste is in paying for it on every push when almost nothing relevant changed.

The good news is that the levers are well understood and they compound. A warm cargo registry cache avoids re-fetching crates, a persisted target directory avoids recompiling unchanged dependencies, incremental compilation avoids rebuilding unchanged code, and a compiler cache like sccache deduplicates object-level work across runs. Stacked together these can make a clean CI build several times faster. The catch is that each lever only pays off if the cache actually survives between jobs, and hosted CI caches are notorious for cold misses, size caps, and re-upload overhead that eat the savings they promise.

Three numbers frame the year for Rust teams. Roughly three quarters of professional developers report using CI/CD, so the baseline of running pipelines on every push is settled. About sixty-three percent of a cold Rust CI minute is spent compiling rather than testing, which is where the optimization budget belongs. And a full warm-cache stack takes a clean build of a mid-size workspace roughly four times faster, turning a slow, expensive pipeline into a predictable one.

Because the compile tax is both so large and so cacheable, Rust is the clearest case in this entire report where the runner layer decides the bill. Warm, persistent caches plus automatic retry of transient compile or network failures are what separate a Rust pipeline that costs a fortune from one that does not, and that is precisely the territory where managed runners change the economics most.

Clean Rust build time as caches are layered on
No cache (cold)612 s+ cargo registry cache498 s+ target dir cache311 s+ warm sccache149 s

Wall-clock for a clean CI build of a mid-size workspace as each cache is added. · Source: Latchkey analysis (modeled)

Hosted runner cost per minute
Linux 2-core$0.008Windows 2-core$0.016macOS$0.08Managed (Latchkey)$0.0025

Published GitHub-hosted per-minute rates vs a managed alternative. · Source: GitHub Actions pricing + Latchkey rates

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.

In Rust, the compiler is your biggest CI line item

Across most languages testing dominates the billed minute, and the standard optimization playbook reflects that: shard the tests, run them in parallel, quarantine the slow ones. Rust breaks that assumption. On a cold runner roughly sixty-three percent of the minute is spent producing artifacts before a single test executes, which means the test suite is not where the money goes and not where the savings live.

This inverts the usual advice in a way that trips up teams arriving from other ecosystems. Shaving test time barely moves a Rust pipeline, because tests are a minor share of the clock. Shaving compile time moves everything, because compilation is the clock. A team that spends a sprint parallelizing its Rust test suite and ignores the build cache will be disappointed by the result, while a team that does the opposite will see the pipeline transform.

The practical consequence is that the entire cost-reduction strategy for a Rust pipeline should start at the build cache and work outward from there. Everything else, the test sharding, the profile discipline, the linting cadence, is a second-order optimization layered on top of a build that is already warm. Get the compile caching right first, and the rest of the levers start to matter; get it wrong, and they barely register against the cold-build cost.

Where a Rust CI minute goes
Compile (deps + crate) 63%
cargo test execution 19%
clippy + fmt + registry fetch 12%
Re-runs from transient failures 6%

Modeled split of a billed minute for a typical cold Rust workspace pipeline. · Source: Latchkey analysis (modeled)

sccache plus a persisted target directory is the single biggest win

Caching in Rust compounds in a way that is genuinely satisfying to watch. Starting from a cold clean build of a mid-size workspace at roughly 612 seconds, adding the cargo registry cache brings it down a little, persisting the target directory cuts it substantially, and adding a warm sccache takes it to about 149 seconds. That is a 4.1x speedup from layering caches that do not overlap in what they avoid.

The dominant contributors are the target directory cache and sccache, and they earn their keep for different reasons. The target cache avoids recompiling dependencies that have not changed, which is most of them on most pushes. sccache goes a level deeper and deduplicates object-level compilation across runs and even across branches, so work done once is not redone when the same inputs reappear. Together they attack both the dependency layer and the incremental crate layer.

The crucial caveat is that both only deliver when the cache survives across runs rather than being rebuilt and re-uploaded each job. A target cache that is unpacked, used, and then re-archived on every run can spend nearly as long moving the cache as it saves by using it. The warm number stays warm only when the cache is restored as a persistent volume, not downloaded and unpacked from scratch, which is the structural reason hosted caching underperforms here.

Pick the cheapest profile that still proves what you need

cargo profiles vary enormously in compile cost, and most teams pay for far more than they need on every push. A full release build with optimization on costs nearly three times a plain debug build, and a debug build that carries test debug info costs half again more than a bare one. cargo check, which type-checks without producing a runnable binary, costs a fraction of any of them.

Many per-push checks do not need an optimized binary at all. A pull request that wants to know whether the code compiles and the tests pass needs cargo check and a debug test build, not a release build. Reserving the optimized release profile for tags, nightly runs, and actual release artifacts avoids paying release-grade compile time on every commit, which on a busy repository is a large recurring saving for zero loss of signal.

Profile discipline is free and frequently overlooked precisely because it is invisible. A workflow that defaults to building in release mode looks correct and produces correct results; it just costs two to three times what it needs to. Auditing which jobs actually need which profile, and matching the profile to the question each job is answering, is one of the cheapest optimizations available to a Rust team.

Build cost by cargo profile
check (cargo check)0.4 xdev / debug1 xtest (with debug info)1.5 xrelease (optimized)2.7 x

Relative compile minutes for the same workspace across build profiles. · Source: Latchkey analysis (modeled)

Hosted cache limits quietly cap your Rust savings

A Rust target directory for a real workspace is large, often large enough to bump against the per-repository size caps that hosted CI caches impose. When that happens the cache is evicted, truncated, or skipped, and the failure is silent: the job runs, the tests pass, and the team believes it is cached while quietly paying the cold-build price on every run.

The re-upload overhead makes it worse. Even when a hosted cache fits, it is downloaded and unpacked at the start of the job and re-archived and uploaded at the end, and for a multi-gigabyte target directory that transfer can rival the compile time it was meant to save. The cache becomes a wash, or occasionally a net loss, and nobody notices because the timing is buried inside a step that was always slow.

Persistent caches without per-repo size caps, restored as a warm volume rather than re-downloaded and unpacked each job, are what keep the warm number warm. This is the specific, structural reason managed runners beat hosted caching for Rust rather than a general claim that managed is faster: Rust's cache artifacts are large enough that the caching mechanism itself, not just the cache hit rate, decides whether the savings survive.

Transient failures are unusually expensive in Rust

In most ecosystems a flaky failure costs a re-run of a fast test. In Rust it can cost a re-run of a long compile. A flaky network fetch from the crate registry, an out-of-memory kill on a heavy compilation unit, or a transient linker failure can force the pipeline to repay minutes of compilation, which can exceed the entire test budget of a pipeline in another language.

This makes the mechanical-flake problem sharper for Rust than for almost any other stack. The transient categories, network blips, registry timeouts, OOM kills on undersized runners, are the same ones that plague every pipeline, but the penalty per incident is magnified by the compile tax sitting behind every red build. A two percent flake rate hurts more when each spurious failure repays a five-minute build.

Self-healing runners retry these transient classes automatically, on a fresh environment, before a human sees the red check, so the team is not repaying compilation because a registry timed out for a second. Combined with the managed model's lower effective per-minute cost, this is what turns Rust's long, cacheable pipeline into a predictable one, and it is part of why elite teams hold change-failure rate in the 0-15% band: their pipelines fail on real defects, not on infrastructure hiccups.

The build-time tax makes managed economics decisive for Rust

Rust CI is long-running, cache-sensitive, Linux CPU work, which is the worst possible fit for paying hosted per-minute rates on every cold build. A self-hosted fleet sized for peak compile load sits idle between pushes, and a fleet sized for the average starves builds during peak, so either way the spiky, compile-heavy load wastes capacity. The spreadsheet comparison of instance price to hosted rate hides that idle cost.

Managed runners capture most of the per-minute compute savings while removing the idle and the operations, and at roughly 70% below GitHub-hosted rates the per-minute term alone is material on a pipeline that burns minutes compiling. But the larger effect is that managed runners persist the caches and keep the toolchain warm, so they cut the number of minutes a Rust build needs in the first place, not just the price of each one.

The two effects multiply. A managed runner that costs less per minute and needs fewer minutes because its caches are warm is not adding two savings, it is compounding them, and on a compile-dominated pipeline the compounding is large. For a Rust team without a dedicated platform group to babysit a self-hosted fleet and tune its caches, the managed model is not a marginal improvement, it is the difference between a CI bill that scales with the codebase and one that scales with the change.

  • Rust CI is spiky, compile-heavy Linux work that wastes a self-hosted fleet sized for either peak or average.
  • Managed runners price close to self-hosted compute while removing idle and ops; Latchkey targets roughly 70% below GitHub-hosted rates.
  • Persistent warm caches cut the minute count as well as the per-minute rate, and the two savings compound.

What the fastest Rust teams do differently

The Rust teams with the fastest pipelines treat the build cache as a first-class part of the workflow rather than an afterthought. They persist the target directory and run a warm sccache, they scope cache keys to the lockfile and toolchain version so the cache neither serves stale objects nor misses on every run, and they measure the cache hit rate the way other teams measure test coverage.

They also apply profile discipline as a matter of routine. Per-push checks run cargo check and debug test builds; release builds are reserved for tags and nightly jobs. And they lean on automatic recovery for the transient failures that would otherwise force a repeat of a long compile, so a registry blip costs a quiet retry rather than a full cold rebuild and a developer's attention.

  • Persisted target directory and warm sccache, restored as a volume rather than re-downloaded each job.
  • Cache keys scoped to the lockfile and toolchain version, with the hit rate monitored over time.
  • Profile discipline: cargo check and debug builds per push, release reserved for tags and nightly.
  • Automatic retry of transient compile, network, and OOM failures so red builds do not repay compilation.
  • A runner layer sized for compile-heavy bursts so peak load does not starve or idle the fleet.

Recommendations

Start optimization at the build cache, not the test suite

In Rust the compiler, not the tests, dominates the billed minute, so the standard advice to parallelize tests barely moves the pipeline. Layer the cargo registry cache, a persisted target directory, and a warm sccache first; everything else is second-order until the build is warm.

Persist the target directory as a volume, not an archive

A Rust target cache is large enough that downloading, unpacking, and re-archiving it can cost as much as the compile it saves. Restore it as a warm persistent volume so the speedup survives, and avoid hosted caches whose per-repo size caps silently evict it and drop you back to cold-build cost.

Apply profile discipline on every workflow

A release build costs nearly three times a debug build. Run cargo check and debug test builds on per-push CI, and reserve the optimized release profile for tags, nightly runs, and actual release artifacts. Matching the profile to the question each job answers is a free recurring saving.

Auto-heal transient compile and network failures

In Rust a flaky registry fetch or an OOM-killed compile unit forces a repeat of minutes of compilation, far more expensive than a flaky test elsewhere. Retry transient failures automatically on a fresh environment so a red build never makes the team repay a cold compile for an infrastructure hiccup.

Size runners for compile-heavy bursts

Rust CI load is spiky and compile-bound, which wastes a self-hosted fleet sized for either peak or average. An elastic managed layer that scales to the burst and persists warm caches cuts both the per-minute rate and the minute count, and the two savings compound on a compile-dominated pipeline.

Outlook

Expect compile caching to remain the defining variable in Rust CI economics through 2026 and into 2027. As workspaces grow and dependency graphs deepen, the gap between a team running warm persistent caches and one re-paying cold builds widens with the codebase, because the cold-build cost grows with the project while the warm-build cost grows only with the change. The teams that get caching right early compound that advantage as they scale.

The tooling around the build cache is maturing in the same direction. sccache, incremental compilation, and registry caching are converging on an expectation that build work done once is not redone, and the remaining differentiator is increasingly the runner layer's ability to keep those caches persistent and warm rather than ephemeral. That is a structural advantage for managed runners that does not depend on Rust's compiler getting any faster.

For most Rust teams the practical takeaway is that the long, expensive pipeline is not a fact of life to be endured, it is a caching problem to be solved. A warm target directory, a shared sccache, profile discipline, and automatic recovery for transient failures turn the build-time tax from a recurring surprise into a predictable, modest cost, and they do it without making the application any less safe or any less fast at runtime.

Methodology

This report focuses on the Rust CI pipeline: compile-time dominance, sccache and incremental compilation, cargo registry and target caching, and cost by build profile. Build timings, minute-split, and profile-multiplier figures are Latchkey modeled estimates derived from typical mid-size workspace shapes and published GitHub-hosted runner pricing, intended to show direction and magnitude rather than a precise population value. The CI adoption headline is from the Stack Overflow Developer Survey. 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