Speed Up Rust Compile Times with sccache, mold, and cargo-nextest
Wire a compilation cache, a faster linker, and a parallel test runner into your Rust project.
What you'll build
You'll take an existing Rust workspace and cut its clean-build, rebuild, and test times by wiring in three tools: sccache (a compilation cache that survives cargo clean and fresh CI runners), mold (a drop-in faster linker), and cargo-nextest (a parallel, process-per-test runner). Everything lands in two config files and three installed binaries — zero source changes.
Prerequisites
- OS: Linux x86_64 (commands shown for Ubuntu 22.04+/Debian 12). sccache and nextest also work on macOS and Windows; mold produces ELF output only, so macOS readers should skip step 3 — Apple's linker and Rust's bundled
rust-lldalready cover you. - Rust: a stable toolchain via rustup. Verified against Rust 1.97.1.
- clang: any recent version (
sudo apt install clang) — it's the linker driver that hands off to mold. - Tool versions verified for this tutorial: sccache 0.17.0, mold 2.41.0, cargo-nextest 0.9.143.
- A Rust project with a test suite. Every command below is project-agnostic, so use a real one — the bigger the dependency tree, the bigger the win.
1. Record a baseline
You can't claim a speedup you didn't measure. From your project root:
cargo clean
time cargo build
time cargo test
Write both numbers down. Also note the incremental case — touch one file, time cargo build again — since that's the build you do a hundred times a day.
2. Wire in sccache
sccache wraps every rustc invocation and caches the output keyed on the exact inputs, so recompiling the same crate — after a cargo clean, in a second checkout, or on a CI runner with a shared backend — becomes a cache read.
Install it:
cargo install sccache --locked
(Prebuilt binaries exist on the GitHub releases page, and brew install sccache works on macOS, if you'd rather not compile it.)
Then tell cargo to route every compile through it, in ~/.cargo/config.toml:
[build]
rustc-wrapper = "sccache"
Two limitations to know, straight from the docs: sccache can't cache incremental compilation, and it can't cache crates that invoke the linker (bin, dylib, cdylib, proc-macro). In practice that's fine locally — cargo only compiles workspace members incrementally, so your dependency tree (usually 90% of a clean build) caches, while your own crates pass through untouched. In CI, set CARGO_INCREMENTAL=0 so workspace crates become cacheable too.
Prime the cache and watch it pay off:
cargo clean && cargo build # cold: all cache misses, roughly baseline speed
cargo clean && cargo build # warm: dependency compiles come from cache
The second run is where clean-build time collapses.
3. Switch the linker to mold
Linking is single-file-dominated and runs on every rebuild, which makes it the bottleneck for the edit-compile-test loop. mold parallelizes it aggressively.
One honest caveat first: since Rust 1.90, x86_64-unknown-linux-gnu already defaults to LLD, which the Rust project measured at 7× faster linking than GNU ld. So the dramatic numbers in older mold blog posts assume a slower starting point than you have today. mold still beats LLD, but the margin grows with binary size — measure on your project.
Install and configure:
sudo apt install mold
(Distro packages lag upstream a bit; build from source per the mold README if you want 2.41.0 exactly.)
Add to your project's .cargo/config.toml (create the .cargo directory if needed):
[target.'cfg(target_os = "linux")']
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
clang is used as the driver because it accepts -fuse-ld unconditionally; GCC only accepts mold as a value from 12.1.0 on. To try mold once without touching config, prefix any build with mold -run cargo build.
4. Run tests with cargo-nextest
nextest runs every test in its own process and schedules them in parallel across all cores, which is both faster than cargo test's per-binary threading and better isolated — one segfaulting test can't take down its siblings.
Install a prebuilt binary (compiling it via cargo install cargo-nextest --locked also works):
curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
Run your suite:
cargo nextest run
One gap by design: nextest can't run doctests (a stable-Rust limitation), so keep cargo test --doc as a separate step if you have them.
Verify it works
sccache — after the two builds from step 2:
sccache --show-stats
Compile requests 312
Compile requests executed 290
Cache hits 275
Cache hits (Rust) 275
Cache misses 12
Cache hits rate 95.82 %
Cache location Local disk: "/home/you/.cache/sccache"
Version (client) 0.17.0
Your numbers will differ; the line that matters is a high Cache hits rate after the second clean build. (sccache --zero-stats resets counters between experiments.)
mold — linkers sign their work in the binary's .comment section:
readelf -p .comment target/debug/<your-binary> | grep mold
[ 2c] mold 2.41.0 (compatible with GNU ld)
Any mold line means the switch took.
nextest — you should see per-test lines and a summary:
Starting 48 tests across 6 binaries
PASS [ 0.011s] myapp config::tests::parses_defaults
...
------------
Summary [ 0.982s] 48 tests run: 48 passed, 0 skipped
Finally, rerun your step 1 timings and compare.
Troubleshooting
error: linker 'clang' not found — rustc can't find the driver named in your config. sudo apt install clang, or if your GCC is 12.1+, delete the linker = "clang" line and let the default cc pass -fuse-ld=mold.
clang: error: invalid linker name in argument '-fuse-ld=mold' — clang couldn't locate mold on PATH. Install it (step 3) or point at it absolutely: rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/mold"].
sccache shows zero cache hits — expected on the first cold build; hits only appear when the same compile happens twice. If a second clean build still misses, check --show-stats for non-cacheable calls: incremental compilation is the usual culprit, so confirm CARGO_INCREMENTAL=0 in CI, and remember linker-invoking crates never cache.
error: no such command: 'nextest' — the binary isn't on cargo's PATH. Confirm it landed in ~/.cargo/bin (the tar in step 4 must extract there) and that ~/.cargo/bin is in your PATH.
Next steps
Take the same wins to CI: sccache's GitHub Actions cache backend (SCCACHE_GHA_ENABLED, see docs/GHA.md in the repo) or an S3/Redis backend shares one cache across your whole team, and taiki-e/install-action@nextest installs nextest in one workflow line. Profile what's still slow with cargo build --timings — it renders an HTML report showing which crates serialize your build. And dig into nextest's config for CI sharding (--partition), automatic retries for flaky tests, and JUnit output.
Sources & further reading
- sccache - Shared Compilation Cache — github.com
- sccache docs: Rust usage and caveats — github.com
- mold: A Modern Linker — github.com
- cargo-nextest documentation: Installation and running — nexte.st
- Faster linking times with 1.90.0 stable on Linux using the LLD linker — blog.rust-lang.org
- Rust Versions — releases.rs
Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.
Discussion 0
No comments yet
Be the first to weigh in.