On this page
Workspace and Project Management
When a project contains multiple interdependent crates (such as a core library + API server + CLI), a workspace allows them to share the same Cargo.lock and target directory—enabling compilation cache reuse and unified dependency versions. The [patch] feature allows temporarily replacing a dependency's source code during development, while build.rs executes code generation before compilation.
Workspace: Multiple Crates in a Single Repository
When a project contains multiple interdependent crates (such as a core library + API server + CLI), placing them in a workspace offers three main benefits:
[workspace]
members = ["crates/core", "crates/api", "crates/cli"]
resolver = "2"
- Shared build artifacts: All members share a single
target/directory—dependencies are compiled only once, significantly reducing disk usage and compilation time. - Consistent versions:
Cargo.lockis shared at the workspace level—every member sees the same versions of dependencies. - Internal cross-referencing:
apican directly referencecoreusingpath = "../../crates/core"(no need to publish to crates.io).
[workspace.dependencies]: Shared Version Declarations
Starting with version 1.64, you can declare versions in the root Cargo.toml, and members can reference them by key:
[workspace.dependencies]
serde = "1"
tokio = { version = "1", features = ["full"] }
# Each member: [dependencies] → serde = { workspace = true }
This solves the classic problem in multi-crate projects where dependency versions are scattered across various files, leading to missed updates during upgrades. Change the version in one place, and all members update accordingly.
[patch]: Temporarily Replace Dependencies
When an upstream crate has a bug and you need to use a fork until the upstream fixes it:
[patch.crates-io]
serde = { git = "https://github.com/myfork/serde", branch = "fix" }
Note: The version specified in [patch] must be globally compatible within the workspace—if one member depends on serde 1.0 and another on serde 1.3, the fork must satisfy the API requirements of both. This is why forks should ideally only modify internal logic and not public APIs.
Advanced build.rs
// build.rs — executed before compiling the main code
build.rs is commonly used for: compiling C/C++ dependencies (via the cc crate), detecting the presence of system libraries, generating code (e.g., protobuf, OpenAPI), and setting feature flags.
References
- Cargo Book: workspaces, build scripts
- cc crate: docs.rs/cc
Keywords: workspace, members, patch, build.rs, shared dependencies, multi-crate, Cargo.lock