Rust Build Analysis and Optimization
Diagnose slow Rust builds by measuring first, then apply the smallest fix that
targets the actual bottleneck. The useful outcome is: a baseline number, a
named bottleneck backed by profiler output, applied configuration changes, and
a re-measured result — not a pile of speculative config.
Path note: <skill-dir> below means this skill's own directory. Substitute
the literal path announced when the skill loads; do not use $SKILL_DIR.
Hard Rules
- Never recommend a fix before at least one measurement supports it.
- Label every nightly-only or platform-specific option as such.
- Do not silently change settings that affect release runtime performance
(
codegen-units, lto, opt-level in [profile.release]); state the
tradeoff and get agreement.
- Re-measure after applying changes and report before/after numbers.
Step 1 — Frame the Complaint
Establish three facts before touching anything:
- Cold or warm? Full build after
cargo clean / dependency bump, or an
incremental rebuild after a one-line change? They have different
bottlenecks and different fixes.
- Which profile?
dev, release, or CI. Ask, or read the command the
user actually runs.
- Baseline. Time the exact complained-about scenario once, e.g.
cargo build --release after touch-ing a source file for warm builds.
Also check the trivial win first: if the user's inner loop is "edit → build →
read errors", cargo check (or bacon / cargo watch -x check) skips
codegen entirely and is often the single biggest quality-of-life fix.
Step 2 — Measure
Start with the built-in profiler:
cargo build --timings # writes target/cargo-timings/cargo-timing.html
Read it for: slowest units, the concurrency graph (long single-threaded tails
mean a serialization problem), and whether the final bin crate dominates.
Known blind spot: for the warm rebuild of a bin crate, --timings shows one
opaque block — codegen and link time are not broken out. When that block is
the mystery, go deeper with -Zself-profile and measureme
(summarize / flamegraph / crox), cargo-llvm-lines, or linker timing.
Full tool guide: <skill-dir>/references/diagnostics.md.
Step 3 — Classify the Bottleneck
Map the evidence to one of these, in rough order of frequency:
| Evidence |
Bottleneck |
Fix section |
| Final link step slow (big binary, debuginfo) |
Linker |
Linkers |
| One big crate compiles alone at the end, low CPU use |
Oversized crate, serialized codegen |
Workspace splitting |
LLVM_module_codegen / LLVM_lto_optimize dominate self-profile |
Codegen / monomorphization bloat |
Codegen & generics |
| Many slow dependency units on the cold path |
Dependency graph |
Dependency hygiene |
Warm release rebuild redoes everything |
Incremental off (release default) |
Profiles |
| macOS: long tail after codegen |
dsymutil debuginfo packing |
Profiles (split-debuginfo) |
| CI always builds from scratch |
No caching |
CI recipes |
Step 4 — Apply Fixes
Apply fixes matched to the classification, cheapest first. Configuration
recipes with exact Cargo.toml / .cargo/config.toml snippets, platform
support, and maturity notes are in <skill-dir>/references/optimizations.md.
Summary of the menu:
- Linkers — since Rust 1.90 (Sep 2025),
x86_64-unknown-linux-gnu uses
rust-lld by default; on other targets configure lld, mold, or wild.
- Profiles —
debug = "line-tables-only", dep opt-level overrides,
split-debuginfo = "unpacked" on macOS, incremental = true for local
release builds.
- Workspace splitting — the root fix when one crate serializes the build.
- Codegen & generics —
cargo-llvm-lines to find monomorphization bloat;
codegen-units / LTO tradeoffs.
- Nightly accelerators — Cranelift backend for dev,
-Zthreads
parallel frontend (both nightly-only as of 2026).
- CI recipes — sccache,
CARGO_INCREMENTAL=0, a dedicated ci profile,
cargo-chef for Docker.
Step 5 — Verify and Report
Re-run the exact baseline scenario. Report: baseline time, changes applied
(each traceable to a measurement), new time, and the remaining options not
taken with their tradeoffs. If a change did not help, revert it rather than
letting speculative config accumulate.
Routing
- Program runs slowly at runtime → runtime profiling and optimization
(perf/flamegraph on the built binary), not this skill.
- Compiler errors, borrow-checker fights, general Rust questions → normal
coding assistance, not this skill.
- Non-Rust build systems (webpack, gradle, cmake) → out of scope.
1---2name: rust-build-optimization3description: Use when a Rust or Cargo build is slow and the user wants it diagnosed or sped up: profiling compile times with cargo --timings or -Zself-profile, finding whether the bottleneck is dependencies, codegen/LLVM, linking, or one oversized crate, and applying targeted fixes such as faster linkers (lld, mold, wild), incremental compilation, dev/release profile tuning, workspace splitting, Cranelift, the nightly parallel frontend, or CI caching with sccache. Also for reviewing .cargo/config.toml or Cargo.toml profile settings for build speed. Not for making the compiled program run faster (runtime optimization), general Rust coding or debugging questions, or non-Rust build systems.4---56# Rust Build Analysis and Optimization78Diagnose slow Rust builds by measuring first, then apply the smallest fix that9targets the actual bottleneck. The useful outcome is: a baseline number, a10named bottleneck backed by profiler output, applied configuration changes, and11a re-measured result — not a pile of speculative config.1213> Path note: `<skill-dir>` below means this skill's own directory. Substitute14> the literal path announced when the skill loads; do not use `$SKILL_DIR`.1516## Hard Rules1718- Never recommend a fix before at least one measurement supports it.19- Label every nightly-only or platform-specific option as such.20- Do not silently change settings that affect release runtime performance21 (`codegen-units`, `lto`, `opt-level` in `[profile.release]`); state the22 tradeoff and get agreement.23- Re-measure after applying changes and report before/after numbers.2425## Step 1 — Frame the Complaint2627Establish three facts before touching anything:28291. **Cold or warm?** Full build after `cargo clean` / dependency bump, or an30 incremental rebuild after a one-line change? They have different31 bottlenecks and different fixes.322. **Which profile?** `dev`, `release`, or CI. Ask, or read the command the33 user actually runs.343. **Baseline.** Time the exact complained-about scenario once, e.g.35 `cargo build --release` after `touch`-ing a source file for warm builds.3637Also check the trivial win first: if the user's inner loop is "edit → build →38read errors", `cargo check` (or `bacon` / `cargo watch -x check`) skips39codegen entirely and is often the single biggest quality-of-life fix.4041## Step 2 — Measure4243Start with the built-in profiler:4445```bash46cargo build --timings # writes target/cargo-timings/cargo-timing.html47```4849Read it for: slowest units, the concurrency graph (long single-threaded tails50mean a serialization problem), and whether the final bin crate dominates.51Known blind spot: for the warm rebuild of a bin crate, `--timings` shows one52opaque block — codegen and link time are not broken out. When that block is53the mystery, go deeper with `-Zself-profile` and `measureme`54(`summarize` / `flamegraph` / `crox`), `cargo-llvm-lines`, or linker timing.55Full tool guide: `<skill-dir>/references/diagnostics.md`.5657## Step 3 — Classify the Bottleneck5859Map the evidence to one of these, in rough order of frequency:6061| Evidence | Bottleneck | Fix section |62| ----------------------------------------------------------------- | ----------------------------------- | -------------------------- |63| Final link step slow (big binary, debuginfo) | Linker | Linkers |64| One big crate compiles alone at the end, low CPU use | Oversized crate, serialized codegen | Workspace splitting |65| `LLVM_module_codegen` / `LLVM_lto_optimize` dominate self-profile | Codegen / monomorphization bloat | Codegen & generics |66| Many slow dependency units on the cold path | Dependency graph | Dependency hygiene |67| Warm `release` rebuild redoes everything | Incremental off (release default) | Profiles |68| macOS: long tail after codegen | `dsymutil` debuginfo packing | Profiles (split-debuginfo) |69| CI always builds from scratch | No caching | CI recipes |7071## Step 4 — Apply Fixes7273Apply fixes matched to the classification, cheapest first. Configuration74recipes with exact `Cargo.toml` / `.cargo/config.toml` snippets, platform75support, and maturity notes are in `<skill-dir>/references/optimizations.md`.76Summary of the menu:7778- **Linkers** — since Rust 1.90 (Sep 2025), `x86_64-unknown-linux-gnu` uses79 `rust-lld` by default; on other targets configure `lld`, `mold`, or `wild`.80- **Profiles** — `debug = "line-tables-only"`, dep `opt-level` overrides,81 `split-debuginfo = "unpacked"` on macOS, `incremental = true` for local82 release builds.83- **Workspace splitting** — the root fix when one crate serializes the build.84- **Codegen & generics** — `cargo-llvm-lines` to find monomorphization bloat;85 `codegen-units` / LTO tradeoffs.86- **Nightly accelerators** — Cranelift backend for dev, `-Zthreads`87 parallel frontend (both nightly-only as of 2026).88- **CI recipes** — sccache, `CARGO_INCREMENTAL=0`, a dedicated `ci` profile,89 cargo-chef for Docker.9091## Step 5 — Verify and Report9293Re-run the exact baseline scenario. Report: baseline time, changes applied94(each traceable to a measurement), new time, and the remaining options not95taken with their tradeoffs. If a change did not help, revert it rather than96letting speculative config accumulate.9798## Routing99100- Program runs slowly at runtime → runtime profiling and optimization101 (perf/flamegraph on the built binary), not this skill.102- Compiler errors, borrow-checker fights, general Rust questions → normal103 coding assistance, not this skill.104- Non-Rust build systems (webpack, gradle, cmake) → out of scope.