🎓 A1Learner
🔍
0 of 149 lessons completed

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 = true

Link 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.io

Example

// 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?