Rust Workspaces & Publishing
A workspace is Cargo's way to manage several crates as one family. The members share one lockfile and one build folder.
Declare the workspace at the root
The root Cargo.toml holds a [workspace] section and no [package] section. resolver = "3" selects the current resolver:
// Root Cargo.toml — no [package] section here
[workspace]
resolver = "3"
members = ["core", "cli", "api"]Share a version once
List a library version once at the root. Each member then opts in with one short line, so upgrades happen in exactly one place:
// Root Cargo.toml
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
// Inside a member's Cargo.toml — opt in:
serde.workspace = trueLink members with a path
Members do not depend on each other automatically. A member names its sibling as a path dependency in its own Cargo.toml:
// Inside cli/Cargo.toml — link to the sibling crate core
[dependencies]
core = { path = "../core" }Work on all, or on one
Plain cargo commands cover every member. Add -p and a name to build, test, or publish just one:
cargo build # every member
cargo test # every member's tests
cargo build -p core # just the core member
cargo publish -p core # ship core to crates.ioExample
// Root Cargo.toml
// [workspace]
// members = ["core", "cli"]
// [workspace.dependencies]
// serde = { version = "1", features = ["derive"] }
fn main() { println!("workspace: 2 members, 1 lockfile, shared target/"); println!("cargo publish -p core ships the core crate to crates.io"); }Key points
- All members share one Cargo.lock and one target folder
- Before publishing, a crate needs a license, a description, and a repository link in its Cargo.toml
- docs.rs builds your documentation automatically after publishing
- Versions follow semver, and the cargo semver-checks tool can warn you before you break other people's code
In this example, the real workspace setup lives in the comments. A root Cargo.toml names two members, core and cli. It also names a shared serde version. The runnable code prints the two facts that matter. First: 2 members, 1 lockfile, a shared target folder — so a fix in core is tested everywhere at once. Second: the publish command that ships just the core crate. In a real workspace, member crates refer to the shared serde with serde.workspace = true, so version upgrades happen in exactly one place.
Note
A workspace is the monorepo pattern, built into the tool.
Big Rust projects — including many famous ones — are organised exactly this way.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does a workspace share between its member crates?