Overview
Beyond the daily command surface, cargo is a project model:
how multi-crate repositories are laid out (workspaces), how optional functionality is
expressed and resolved (features), how build settings are grouped (profiles), how
native dependencies hook in (build.rs), and how code reaches crates.io. These five
mechanisms are where real-world Rust projects are actually engineered — and where the
sharp edges (feature unification, lockfile drift, build-script abuse) live.
Key points
- Workspaces: one
Cargo.lockand onetarget/for many member crates; a virtual manifest (rootCargo.tomlwith only[workspace]) is the norm for services split intocrates/*.[workspace.dependencies]declares versions once and members inherit withdep.workspace = true— the version-catalog pattern, first-party. - Features are additive flags:
[features]names optional deps andcfg(feature)gates; unification means the build uses the union of features every dependent asks for — so a feature must never change behaviour, only add it. Default features anddefault-features = falseare the slimming levers. - Profiles:
dev(opt-level 0, incremental),release(opt-level 3), plustest/benchinheriting them. The release recipe worth memorizing:lto = "thin"(ortrue),codegen-units = 1,panic = "abort"where unwinding is unneeded,strip = true; custom profiles ([profile.profiling]) cover release-with-debug-info — see Profiling & debugging. build.rsruns before compilation: compile C via thecccrate, generate bindings (bindgen) or protobuf stubs (tonic-build), emitcargo::rustc-link-lib=…/cargo::rerun-if-changed=…directives. Powerful and abused — a heavy build.rs is a supply-chain and build-time liability (it runs arbitrary code at build time, which is why cargo-vet/deny audits exist).- Publishing:
cargo publishuploads an immutable.crateto crates.io — semver discipline enforced socially (and bycargo-semver-checks),cargo yankhides a version from new resolutions without deleting it, owners/teams gate who can publish,rust-version(MSRV) declares the minimum toolchain. - Lockfile semantics:
Cargo.lockpins the exact resolved graph;cargo updatemoves within semver ranges. Commit it for binaries and — per current guidance — for libraries too (CI reproducibility); lib consumers ignore it by design. The MSRV-aware resolver (edition 2024 / resolver v3) can pick older compatible versions for older toolchains. - Registries beyond crates.io:
[registries]config for private ones; git and path dependencies for unpublished code (path deps are local-only — publishing requires a registry version).
Details
Feature unification, the classic trap
If crate A wants serde without derive and crate B wants serde/derive, everyone
gets derive — fine, additive. But if a crate misuses a feature to switch behaviour
(a strict-mode feature, say), unification silently turns it on for dependents who
never asked. Corollaries: features must be additive; mutually-exclusive features are a
design bug (use cfg attributes or separate crates); and cargo tree -e features
answers "why is this feature on?". --all-features in CI plus
cargo hack --feature-powerset on libraries catch the combinations users will hit.
Workspace layout, the house norm
# Cargo.toml (virtual manifest)
[workspace]
members = ["crates/*"]
resolver = "3"
[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
# crates/api/Cargo.toml
[dependencies]
tokio.workspace = true
core = { path = "../core" }
Binaries and their libraries split (api bin + core lib) so integration tests and
benches link the library; shared lints via [workspace.lints].
Related
- The Rust build ecosystem — parent overview and the artifact formats.
- cargo — the front door — the daily command surface over this model.
- Building & releasing — what
happens after
cargo buildworks: cross-compiling, distributing, auditing. - Editions — the
editionkey and resolver versions. - go mod and Go modules — the Go counterpart: MVS resolution vs cargo's semver-max, proxy vs registry.
- Maven / Gradle — the JVM counterparts; cargo profiles ≈ a fixed, blessed subset of what they configure.
- Hexagonal architecture reference implementation — Rust — the house service layout built on the workspace model: crates as architectural walls.