Cargo Workspaces
Cargo Workspaces
Allow you to split your project into several packages
- further encourages modularity
- develop multiple applications and libraries in a single tree
- synchronized dependency management, release process, etc.
- a way to parallelize compilation and speed up builds
- your internal projects should likely be workspaces even if you don't use monorepos
Anatomy of Rust Workspace
my-app/
├── Cargo.toml # a special workspace file
├── Cargo.lock # notice that Cargo produces a common lockfile for all packages
├── packages/ # can use any directory structure
│ ├── main-app/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── admin-app/
│ │ └── ...
│ ├── common-data-model/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── useful-macros
│ ├── service-a
│ ├── service-b
│ └── ...
└── tools/ # packages don't have to be in the same directory
├── release-bot/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── data-migration-scripts/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── ...
Workspace Cargo.toml
[workspace]
resolver = "2"
members = ["packages/*", "tools/*"]
[dependencies]
thiserror = "1.0.39"
...
using wildcards for members is very handy when you want to add new member packages, split packages, etc.
Cargo.toml for a workspace member
[package]
name = "main-app"
[dependencies]
thiserror = { workspace = true }
service-a = { path = "../service-a" }
...
Cargo commands for workspaces
cargo run --bin main-app
cargo test -p service-a
Creating a workspace
#!/usr/bin/env bash
function nw() {
local name="$1"
local work_dir="$PWD"
mkdir -p "$work_dir/$name/packages"
git init -q "$work_dir/$name"
cat > "$work_dir/$name/Cargo.toml" << EOF
[workspace]
resolver = "2"
members = ["packages/*"]
[workspace.dependencies]
EOF
cat > "$work_dir/$name/.gitignore" << EOF
target
EOF
code "$work_dir/$name"
}
Example:
nw spaceship
cargo new --lib spaceship/packages/fuel-control