cargo-rail
Monorepo orchestration for Rust workspaces.
Commands · Config · Examples · Crates.io
Pre-built binaries available on the Releases page.
TLDR
- Only test what changed both locally and in CI:
cargo rail test - Keep manifests clean and unified:
cargo rail unify - Split + sync crates with full git history:
cargo rail split/cargo rail sync - Release in dependency order with changelogs:
cargo rail release
Pure dev tooling. No workspace-hack crate. 11 direct dependencies.
Quick Start
Drop into any Rust workspace:
Optional configuration (auto-detected location):
See docs/commands.md
Workflows
Change Detection & Testing
Only run tests for crates affected by your changes, with nextest auto-detection:
For CI, see cargo-rail-action.
Dependency Unification
Resolution-based [workspace.dependencies] management using Cargo’s resolver:
What it does, per target triple (targets in rail.toml):
- Unifies versions based on what Cargo actually resolved
- Computes MSRV from the resolved graph (
[workspace.package].rust-version) - Prunes dead features that are never enabled
- Detects/removes unused deps (opt-in via config)
- Optionally pins transitives (workspace-hack replacement)
Split & Sync
Extract crates to standalone repos and keep them in sync, with deterministic SHAs.
Three modes: single crate to new repo, multiple crates to new repo, or multiple crates to a new workspace.
Split/sync behavior is driven by [crates.NAME.split] in rail.toml. See docs/config.md
Release
Version bumping, changelog generation, tagging, and publishing in dependency order:
Configure once in rail.toml:
[]
= "v"
= "{crate}-{prefix}{version}" # Adjust for standalone crate
= true
Example Videos
Real workspaces, recorded command workflows end-to-end. All assets live under examples/.
https://github.com/user-attachments/assets/93f34633-aa0e-4cde-8723-c81f3f474bac
https://github.com/user-attachments/assets/520abf55-cf45-43af-8dc8-0eed0a58ce72
https://github.com/user-attachments/assets/31bf5ff5-7185-4e59-acaa-ea8edd3c6f48
https://github.com/user-attachments/assets/3520d254-e69c-460c-b894-eb126b42a1ea
https://github.com/user-attachments/assets/b9f56e77-de0a-42c1-b2ef-1a40bb24f5ac
https://github.com/user-attachments/assets/9c0b6df1-8539-44a0-9c82-a9fdca5e075c
Unification Results in Testing/Validation
cargo rail unify on trusted Rust monorepos:
| Repository | Crates | Deps Unified | Member Edits |
|---|---|---|---|
| tikv | 83 | 57 | 519 |
| polars | 33 | 2 | 13 |
| meilisearch | 19 | 46 | 210 |
| helix | 13 | 16 | 67 |
| tokio | 10 | 10 | 35 |
| ripgrep | 10 | 9 | 41 |
| helix-db | 6 | 16 | 44 |
Full demos and reports live under examples/.
Could Replace
| Tool | cargo-rail equivalent |
|---|---|
| cargo-hakari | unify with pin_transitives = true |
| cargo-udeps, cargo-machete, cargo-shear | unify with detect_unused = true / remove_unused = true |
| cargo-msrv (for dep-driven MSRV) | unify with msrv = true |
| cargo-release, release-plz | release command |
| git-cliff | Built-in changelog generation |
| Google's Copybara for Rust teams | split + sync commands |
| Mountain of shell scripts | test + affected + cargo-rail-action in CI |
Design Notes
I've built cargo-rail as a necessity for my own work. I've explained the reasoning behind it and touched on the plans for the future in this post: Rust Monorepo Tooling. I would love contributions; I'd love to iron out the details and workflows that we all use daily but that are clunky.
Supply-Chain Safety
This matters a great deal to me. I've tried to keep the tool itself lean; avoids large meta-dependency graphs. Currently, cargo-rail depends on 11 core deps; 77 resolved in the release build.
Multi-Target Resolution
Runs cargo metadata --filter-platform per target and computes feature intersection, not union. I often build for 7-9 target-triples; this was a requirement.
System Git > Gix
I've used the git binary directly for deterministic SHAs and proper history, no libgit2/gitoxide. They felt a bit heavy for the use case and we all use Git locally in some fashion.
Lossless TOML
Uses toml_edit so existing comments and layout are preserved. Manipulating TOML is honestly not as easy as it sounds. Please, if you run into any problems... open an 'Issue' and I'll take a look.
Contributions Welcome
Built by @loadingalias