23.11 Cargo Workspaces
Workspaces allow multiple packages (crates) to coexist in one directory structure, sharing dependencies and a single lock file. They are compiled, tested, and (optionally) published together. This approach is ideal for:
- Monorepos: Large projects containing many related crates
- Shared Libraries: Splitting functionality among crates without overhead
- Streamlined Builds: Consistent testing and building across multiple crates
23.11.1 Setting Up a Workspace
Suppose you have two crates, crate_a
and crate_b
, in my_workspace
:
my_workspace/
├── Cargo.toml # Workspace manifest
├── crate_a/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── crate_b/
├── Cargo.toml
└── src/
└── main.rs
The top-level Cargo.toml
might look like:
[workspace]
members = [
"crate_a",
"crate_b",
]
If crate_b
depends on crate_a
, reference it in crate_b/Cargo.toml
via a path:
[dependencies]
crate_a = { path = "../crate_a" }
To build and run:
# Build everything
cargo build
# Build just crate_b
cargo build -p crate_b
# Run the binary from crate_b
cargo run -p crate_b
All crates in the workspace share a single Cargo.lock
, ensuring consistent dependency versions.
The command cargo publish
publishes the workspaces default members.
The default members of a workspace can be set explicitly with the workspace.default-members key in the root manifest. If this is not set, a virtual workspace will include all workspace members.
You can also publish single crates of a workspace with:
# Publish only crate_a
cargo publish -p crate_a
23.11.2 Benefits of Workspaces
- Shared target folder: Avoids duplicate downloads and recompilations.
- Consistent versions: Common
Cargo.lock
ensures uniform dependencies. - Convenient commands:
cargo build
,cargo test
, andcargo doc
can operate on all crates or specific ones.