Rust compile times are the classic CI bottleneck. Caching Cargo and the target directory turns a cold rebuild into an incremental one.
Rust CI is slow because everything compiles from source. Caching the registry, git deps, and compiled artifacts in target/ is the highest-leverage fix.
Use Swatinem/rust-cache
It caches the right paths with a sensible key and prunes stale artifacts automatically.
.github/workflows/ci.yml
- uses:dtolnay/rust-toolchain@stable- uses:Swatinem/rust-cache@v2- run:cargo test --all
What gets cached
The Cargo registry (~/.cargo/registry), git checkouts, and the target/ directory of compiled dependencies. Your own crate still recompiles, but dependencies do not.
Bigger gains on bigger RAM
Linking and codegen are memory-hungry. Right-sized runners with more RAM and fast disk shorten cold compiles. Latchkey runners are right-sized per job, so heavy Rust builds get the memory they need without paying for an oversized GitHub-hosted tier.
Measure before you optimise
Pipeline optimisation usually targets the step people assume is slow. Get the real per-step timings first, because the answer is frequently dependency install or a cold cache rather than the build itself.
Terminal
# per-job timings for the last 20 runs
gh run list --limit 20 --json databaseId,conclusion,createdAt,updatedAt \
--jq '.[] | "\(.conclusion)\t\(.createdAt)\t\(.updatedAt)"'
# per-step timing inside one run
gh run view <run-id> --log | grep -E "^\S+\s+.*Run |##\[group\]" | head -40
Key takeaways
Use Swatinem/rust-cache instead of raw actions/cache.
Cache the registry, git deps, and target/.
More RAM and fast disk shorten cold Rust compiles.
Frequently asked questions
How do I cache Rust and Cargo Builds in CI?
Rust CI is slow because everything compiles from source. Caching the registry, git deps, and compiled artifacts in target/ is the highest-leverage fix.
Use Swatinem/rust-cache?
It caches the right paths with a sensible key and prunes stale artifacts automatically.
What gets cached?
The Cargo registry (~/.cargo/registry), git checkouts, and the target/ directory of compiled dependencies. Your own crate still recompiles, but dependencies do not.
Bigger gains on bigger RAM?
Linking and codegen are memory-hungry. Right-sized runners with more RAM and fast disk shorten cold compiles. Latchkey runners are right-sized per job, so heavy Rust builds get the memory they need without paying for an oversized GitHub-hosted tier.