cargo-rail
Deterministic Rust monorepo orchestration: run only impacted CI surfaces, unify dependency graphs, split/sync crates across repos, and automate releases.
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 |
Why this matters:
- Change Detection (
plan/run) reduces what runs — 68% of measured commits avoided full-run behavior, with explicit plan traces. - Dependency Unification (
unify) reduces graph complexity — cleaner deps, smaller build units, fewer rebuilds. - Toolchain Consolidation keeps workflows in one tool with 14 core dependencies, reducing repeated metadata fetches and plugin sprawl.
Before cargo-rail: run multiple plugins independently (hakari/workspace-hack, udeps, machete, shear, features-manager, msrv, sort, and others), often over separate metadata views.
After cargo-rail: run cargo rail unify --check with 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: CI/CD often runs full pipelines for small changes, or relies on custom scripts that drift from local behavior.
Solution: one planner contract used locally and in CI:
# 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, and integrate withjustfile,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: dependency hygiene usually requires multiple plugins (hakari, udeps, machete, shear, features-manager, msrv, sort, and others), each with separate commands and metadata passes. Undeclared features borrowed from Cargo's resolver can break isolated builds silently.
Solution: cargo rail unify provides one command and one metadata pass for integrated 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 — tune behavior in
rail.toml(unused removal, feature pruning, sorting, and more).
Unused detection combines resolved-graph analysis with rustc diagnostics (unused_crate_dependencies) so deps that are resolved but never referenced are also removed. Optional deps and unconfigured target-gated deps are conservatively skipped.
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 (Copybara Alternative)
Problem: teams often need to develop in a monorepo but publish crates from standalone repos with full history. Existing tools (git subtree, git-filter-repo) are mostly one-way and manual.
Solution: cargo rail split + cargo rail sync — bidirectional sync with 3-way conflict resolution:
# Extract a crate to a 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, and dependency-order publish in one flow, with a lean dependency footprint.
# Cut a new release
This produces changelog entries, tags, crates.io publish, and GitHub release metadata.
GitHub Actions Integration
For CI/CD integration, use cargo-rail-action (uses: loadingalias/cargo-rail-action@v3) — a thin transport over cargo rail plan -f github that handles installation, checksum verification, and output publishing for job gating.
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: Validation protocol | Unify results
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
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md.
Code of Conduct
See CODE_OF_CONDUCT.md.
License
Licensed under MIT.