Workspaces & Feature Flags
npm workspaces → cargo workspaces
Section titled “npm workspaces → cargo workspaces”When a TypeScript monorepo grows beyond a single package, you reach for npm (or pnpm/yarn) workspaces. Cargo has a first-class equivalent: a workspace is a single Cargo.toml at the root that lists member crates. All members share a single Cargo.lock and a single target/ build directory.
# package.json (root){ "name": "my-monorepo", "workspaces": [ "packages/api", "packages/core", "packages/cli" ]}
# packages/core/package.json{ "name": "@my/core", "version": "1.0.0"}# Cargo.toml (root — the workspace manifest)[workspace]members = [ "crates/api", "crates/core", "crates/cli",]resolver = "2" # always use resolver version 2
# crates/core/Cargo.toml[package]name = "core"version = "0.1.0"edition = "2021"Running commands across the workspace
Section titled “Running commands across the workspace”# TypeScript (npm workspaces)npm run test --workspacesnpm run build --workspace packages/api
# Cargocargo build --workspace # build every membercargo test --workspace # test every membercargo build -p api # build only the "api" cratecargo test -p core # test only the "core" crateSharing a dependency version across crates
Section titled “Sharing a dependency version across crates”# Cargo.toml (root workspace manifest)[workspace.dependencies]tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }
# crates/api/Cargo.toml — inherit without repeating the version[dependencies]tokio = { workspace = true }serde = { workspace = true }This prevents version drift across workspace members — a common problem in Node monorepos where different packages silently pull different patch versions.
Feature flags — conditional compilation
Section titled “Feature flags — conditional compilation”Feature flags are Rust’s answer to optional peer dependencies and conditional require() calls. They let consumers opt into extra functionality without paying the compile cost when they do not need it.
[features]default = ["json"] # features enabled by defaultjson = ["dep:serde_json"] # "json" feature pulls in serde_jsonasync = ["dep:tokio"] # "async" feature pulls in tokiofull = ["json", "async"] # convenience: enable everything
[dependencies]serde_json = { version = "1", optional = true }tokio = { version = "1", optional = true }#[cfg(feature = "json")]pub mod json_support { pub fn parse(s: &str) -> serde_json::Value { serde_json::from_str(s).unwrap() }}# Build with no default featurescargo build --no-default-features
# Enable specific featurescargo build --features "async,json"
# Enable all featurescargo build --all-featuresWorkspaces and feature flags require multi-file project layout, so there is no browser Playground for this lesson. Create a workspace locally with
cargo new --liband experiment with the examples above.