Cargo Best Practices
Reproducible, fast, well-organized Cargo workflows keep Rust teams shipping without dependency surprises or slow feedback loops.
How to Use This List
- Apply when scaffolding a new repo or onboarding a service to an existing workspace.
- Use as a PR checklist for manifest changes (
Cargo.toml,build.rs, profiles). - Pair with Dependency Management for ongoing maintenance.
A - Project Structure
- Binary apps commit
Cargo.lock; libraries document lock policy. Reproducible CI and deploys for services. - Use a workspace when you have 2+ related crates. One lockfile and shared
[workspace.dependencies]. - Prefer
crates/layout for growing monorepos. Clear boundaries between API, domain, and CLI. - Set
edition = "2024"andrust-versionconsistently. MSRV documented in README and CI. - Keep
target/and artifacts out of git. Use.gitignoreand Docker layer caching instead.
B - Dependencies
- Pin versions in
[workspace.dependencies]once. Members useworkspace = trueto avoid drift. - Disable
default-featureswhen trimming compile time. Opt in explicitly per crate. - Run
cargo audit(orcargo deny) on a schedule. Security advisories caught early. - Remove unused deps; run
cargo tree -dafter major upgrades. Duplicate majors inflate build time. - Avoid git deps in production without a pinned
rev. Floating branches break reproducibility.
C - Features and Profiles
- Every optional dependency maps to a named feature. Consumers enable capability, not internal module names.
- Test
--no-default-featuresand--all-featuresin CI. Optional code paths do not rot. - Release profile uses
lto = "thin"and tunedcodegen-units. Measure before fat LTO in CI. - Document feature flags in README. Include example
cargo build --features ...lines. - Use custom profiles (
release-fast) for local perf iteration. Do not weaken production profile.
D - Build Scripts and Tooling
-
build.rslistsrerun-if-changedfor all inputs. No stale codegen after proto/config edits. - Prefer
cargo check/clippyin watch loops over fullbuild. Faster developer feedback. - Install
cargo-nextestfor large workspaces. Better parallelism and CI reporting. - Use
cargo expandwhen debugging proc macros. Pair with Debugging Macros. - Cache registry and
target/in CI.sccacheor GitHub Actions cache for Rust projects.
E - Publishing and Releases
-
cargo publish --dry-runbefore every release. Tarball contents and metadata validated. - Semver and changelog for every crates.io publish. Pre-1.0 minors can be breaking; document policy.
- LICENSE files match
licensefield. MIT OR Apache-2.0 dual license is standard. - docs.rs metadata enables
all-featureswhen safe.package.metadata.docs.rsconfigured. - Yank bad releases; never rely on deletion. Follow up with patch release and advisory note if needed.
FAQs
Minimum CI for Cargo projects?
cargo fmt --check, cargo clippy --workspace -- -D warnings, cargo test --workspace, optional cargo audit.
Workspace root with no package?
Virtual workspace is fine; set default-members for cargo run ergonomics.
How do I speed up clean builds?
Split hot crates, reduce features, use linker mold, and cache dependencies in CI.
Should I check in `Cargo.lock` for workspaces?
Yes at workspace root for applications; libraries published to crates.io often omit member locks except the workspace root policy you document.
When is build.rs required?
Only for codegen, native linking, or cfg discovery. Do not use it for tasks better handled by xtask or CI scripts.
How do I enforce MSRV?
rust-version in manifest plus cargo +1.97.0 check job in CI matrix.
What about vendoring?
cargo vendor for air-gapped or policy-constrained environments; adds maintenance overhead.
How do I handle breaking dependency majors?
Dedicated upgrade PR with changelog review, cargo test --workspace, and possible API shim crate.
Are patch sections OK?
[patch.crates-io] for temporary forks only; remove when upstream releases fix.
How do I document build commands?
README with cargo run, feature flags, and env vars; link to .cargo/config.toml if non-default.
Related
- Cargo Basics - getting started
- Workspaces - monorepo layout
- Dependency Management - updates and audit
- Linting in CI - quality gates
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.