cargo-rail
A deterministic, cargo-native control plane for Rust monorepos: build/check/test/bench only what changes locally and in CI, unify the graph (deps/features), split/sync crates into new repos/monorepos, and automate releases with 14 core dependencies.
Why
Documented change-detection impact on real repos (tokio, helix, meilisearch, helix-db):
| Metric | Impact |
|---|---|
| Commits Measured | 80 (20 per repo) |
| Could Skip Build | 21% |
| Could Skip Tests | 19% |
| Targeted (Not Full Run) | 68% |
| Dependencies Unified | 132 across 53 crates |
Undeclared features Fixed |
258 silent bugs prevented |
| MSRV Computation | Automatic from dependency graph |
Compounding effects = massive time/cost savings:
- Change Detection (
plan/run) reduces what runs — 68% of measured commits avoided full-run behavior, with explicit plan traces. - Dependency Unification (
unify) reduces build graph complexity — cleaner deps, smaller build units, fewer rebuilds - Smaller Build Graphs cargo-rail uses 14 core-deps for automatically removing unused dependencies, pruning truly dead features, unifying undeclared features, computing MSRV, splitting and synching crate/s to new, clean repos, and the entire release workflow w/ changelog generation. This results in fewer tools and less cargo-metadata fetches.
Before cargo-rail: Run 6 tools separately (hakari and/or workspace-hack, udeps, machete, shear, features-manager, msrv, sort, and more), each with different data/timing
After cargo-rail: cargo rail unify --check in one metadata call
Quick Start
# install
# generate config
# dependency hygiene
# deterministic planning + execution
Pre-built binaries: GitHub Releases
Workflows
Change Planning (detection) + Execution (plan / run)
Problem: CICD wastes resources testing unchanged code. We either (1) test everything on every commit, or (2) build custom scripts that drift from local behavior.
Solution: One planner contract, used everywhere:
# Local: what would CI run if I pushed this branch?
# CI: deterministic plan → selective execution
How to use this effectively:
- Configure change detection rules in
.config/rail.toml(infrastructure files, doc-only changes, custom, etc.) - Run
planto see impact classification (which surfaces: build, test, bench, docs, infra, custom) - Run
runto execute only selected surfaces — locally or in CI - or wire tojustfile,makefile,xtask, or shell scripts. - Use
--explainto understand any decision: "why did this run?" / "why was this skipped?"
Result: 21% build skip, 19% test skip, 68% targeted/non-full runs across 80 measured commits (tokio/helix/meilisearch/helix-db). See: Examples.
Dependency Unification (unify)
Problem: We all juggle 6+ cargo plugins for dependency hygiene (hakari, udeps, machete, shear, features-manager, msrv, sort, etc.). Each runs separately, on different data, with different CLI patterns... pulling the same cargo-metadata over and over. Undeclared features (borrowed from Cargo's resolver) break isolated builds silently.
Solution: cargo rail unify — one command, one metadata call, comprehensive analysis:
What it does:
- Unifies versions — writes to
[workspace.dependencies], converts members to{ workspace = true } - Fixes undeclared features — detects features borrowed via Cargo's unified resolution
- Prunes dead features — removes features never enabled in resolved graph
- Detects unused deps — flags dependencies not used anywhere
- Computes MSRV — derives minimum Rust version from dependency graph
- Replaces workspace-hack — enable
pin_transitivesfor cargo-hakari equivalent - Configurable - we all have different ideas about what clean means, such as whether to remove unused dependencies or prune features or sort manifests - that's what your
rail.tomlfile is for.
Validated impact on real repos:
| Repository | Crates | Deps Unified | Undeclared Features | MSRV Computed |
|---|---|---|---|---|
| tokio-rs/tokio | 10 | 13 | 7 | 1.85.0 |
| helix-editor/helix | 14 | 28 | 19 | 1.87.0 |
| meilisearch/meilisearch | 23 | 70 | 215 | 1.88.0 |
| helixdb/helix-db | 6 | 21 | 17 | 1.88.0 |
| Aggregate | 53 | 132 | 258 | — |
Config files and validation artifacts: Examples | Validation Forks
Split + Sync (Google Copybara Replacement)
Problem: We need/want to publish crates from monorepos but want clean standalone repos with full git history. I wanted to build in a canonical dev monorepo, but release crates independently. Google'sCopybara requires so much and it's built w/ Java. Existing tools (git subtree, git-filter-repo) are one-way and manual. This offers us a bidirectional sync engine w/ 3-way merge conflict resolution in the event we need it; it never merges to main w/o a review PR for the canonical repo.
Solution: cargo rail split + cargo rail sync — bidirectional sync with 3-way conflict resolution:
# Extract crate to standalone repo with full git history
# Bidirectional sync
Three modes:
single: one crate → one repo (most common)combined: multiple crates → one repo (shared utilities)workspace: multiple crates → workspace structure (mirrors monorepo)
Built on system git (not libgit2) for deterministic SHAs and full git fidelity with less attack surface/weight in the graph.
Release Automation (release)
Release checks, versioning, changelogs, tags, dependency-order publish. Release_plz is great, but it's pulling in something like 500 deps to release our work. That's too much weight to carry around in the graph and too much attack surface in my world. I release cargo-rail with 1cargo-rail.
# Cut a new release
This gives me a clean changelog, tags, crates.io / Github release.
GitHub Actions Integration
For CICD integration, use cargo-rail-action — a thin transport over cargo rail plan -f github that handles installation, checksum verification, and output publishing for job gating. It will make output cleaner and more readable.
The action keeps CI behavior aligned with local plan + run workflows.
Config
cargo rail initgenerates.config/rail.toml.cargo rail config syncupdates.config/rail.tomlwith latest defaults from new releases installed.cargo rail config validatevalidates.config/rail.tomlfor when you're unsure.
By default, on cargo rail init, the rail.toml file is written to the .config/ directory. It's created if it doesn't exist. However, you can move/change it to the workspace root if you prefer it there. You can also 'unhide' the file if you'd like. Reference
Full documentation:
Migration Guides
Tested & Proven On Large Repos
All core workflows (plan/run, unify) validated on production repos with full git history:
| Repository | Crates | Validation | Fork |
|---|---|---|---|
| tokio-rs/tokio | 10 | Unify (13 deps, 7 features), Plan/run | Fork |
| helix-editor/helix | 14 | Unify (28 deps, 19 features), Plan/run | Fork |
| meilisearch/meilisearch | 23 | Unify (70 deps, 215 features), Plan/run | Fork |
| helixdb/helix-db | 6 | Unify (21 deps, 17 features), Plan/run | Fork |
Validation forks: cargo-rail-testing — full configs, integration guides, and reproducible artifacts.
How to Validate:
- Reproducibility: Every command in examples/validation-protocol.md runs on forked repos with real merge history
- Metrics collection: Automated scripts measure execution reduction, surface accuracy, plan duration, unify impact
- Quality audit: Heuristics flag potential false positives/negatives for human review
- Real-world scenarios: Tests run on actual merge commits and real dependency graphs, not synthetic fixtures
Unify results (4 repos, 53 crates):
- 132 dependencies unified to
[workspace.dependencies] - 258 undeclared features fixed (silent bugs prevented)
- 2 dead features pruned
- MSRV computed for all repos (1.85.0 - 1.88.0)
Full protocol and raw artifacts: examples/README.md
Examples
Each workflow includes working config files and reproducible command sequences:
| Workflow | Examples | Real-World Configs |
|---|---|---|
| Change detection | examples/change_detection/ | tokio, helix, meilisearch |
| Unify | examples/unify/ | Validation results |
| Split/sync | examples/split-sync/ | — |
| Release | examples/release/ | — |
Full validation configs: Each fork in cargo-rail-testing includes:
.config/rail.toml— production-ready configdocs/cargo-rail-integration-guide.md— step-by-step integrationdocs/CHANGE_DETECTION_METRICS.md— measured impact analysis
Getting Help
- Issues: GitHub Issues
- Crate: crates.io/cargo-rail
License
Licensed under MIT.