Cargo already knows your workspace. Stop teaching it to ten other tools.
Cargo-Rail turns Cargo's resolved graph into one monorepo engine. unify replaces the dep-hygiene stack. plan and run execute only affected work. Verified compiler reuse survives cargo clean. change and release turn reviewed changesets into version bumps, changelogs, dep-ordered publication, and resumable exact-SHA releases. split and sync keep standalone crates tied to monorepo source and history.
Keep Cargo. Delete the Rest.
Rust monorepos usually acquire a tool for every symptom. Each tool reconstructs part of the same workspace, carries its own configuration, and makes decisions against a slightly different model.
Cargo-Rail replaces that collection with one local, Cargo-native engine:
| Retire | Use | What changes |
|---|---|---|
cargo-hakari, cargo-udeps, cargo-shear, cargo-machete, feature auditors, workspace-inheritance checks, and MSRV scripts |
cargo rail unify |
One reviewable and reversible graph-repair plan |
dorny/paths-filter, YAML path globs, and package-selection scripts |
cargo rail plan and cargo rail run |
Affected work derived from Git and the resolved Cargo graph |
Persisted target/ directories and local cache glue |
Verified compiler reuse | Exact reusable results remain available across target directories in one source root and after cargo clean |
release-plz, cargo-release, git-cliff, and publish-order scripts |
cargo rail change and cargo rail release |
Reviewed release intent carried through exact-SHA publication and recovery |
| Copybara or custom monorepo-to-crate scripts | cargo rail split and cargo rail sync |
Cargo-aware synchronization with source history and recovery evidence |
Cargo-Rail does not coordinate those tools behind the scenes. It replaces the duplicated workspace models they require and shares the same contextual authority.
flowchart TB
source["Git History + Cargo"] --> rail["Cargo-Rail"]
rail --> unify["unify<br/>coherent dependencies"]
rail --> plan["plan / run<br/>affected execution"]
rail --> cache["verified reuse<br/>compiler results"]
rail --> release["change / release<br/>exact-SHA publication"]
rail --> sync["split / sync<br/>crate repositories"]
No hosted service. No second build language. No hand-rolled crate maps.
Cargo, nextest, GitHub Actions, your task runner, and your runners remain in place. Cargo-Rail just makes them do less work and consume fewer resources.
Install Cargo-Rail and inspect a real branch:
cargo install cargo-rail --locked
cargo rail plan --merge-base --explainplan is read-only. It does not execute selected work or edit tracked files.
Preview the exact commands Cargo-Rail would run:
cargo rail run --merge-base --dry-run --print-cmd --explainThen keep the rest of your toolchain and execute only affected CI work:
cargo rail run --merge-base --profile ciThe built-in ci profile runs selected build and test actions. Existing jobs can consume the same versioned plan through cargo-rail-action, JSON, or GitHub output.
Dependency hygiene is not six unrelated lint problems. It is one graph-coherence problem.
cargo rail unify --check --explainOne pass detects and plans repairs for:
- dependency-version drift;
- hidden feature coupling;
- unused dependency edges;
- workspace-inheritance drift;
- MSRV mismatches; and
- transitive feature unification normally handled through a generated workspace-hack crate.
Graph-removing decisions carry compiler evidence. Cargo-Rail validates the resulting Cargo graph before applying lossless TOML edits.
Apply with a backup:
cargo rail unify --backupReview the resulting diff, or restore the latest backup:
cargo rail unify undoOne install. One configuration. One report. One explanation format. One rollback path.
That is the real replacement for a directory full of Cargo plugins and maintenance scripts.
A path filter can tell you which directory changed. It cannot reliably tell you what the change affects.
Cargo-Rail interprets the change before selecting work:
changed source
→ semantic manifest and lockfile analysis
→ Cargo package ownership
→ reverse-dependency impact
→ build / test / docs / bench / infra / custom surfaces
→ surface-specific Cargo scope
→ validated commands and CI outputs
A formatting-only manifest edit can select no package work. A shared-library change can select its affected dependent closure. Infrastructure changes can select repository-level actions without pretending they belong to a crate.
When planning evidence is incomplete, Cargo-Rail widens the scope instead of guessing narrowly.
The same versioned plan drives:
- human explanations;
- JSON and GitHub output;
- dry-run command previews;
- direct execution; and
- durable decision receipts.
There is only one implementation of “affected.”
Normal Cargo reuse is tied to the target directory. Remove that directory or run:
cargo cleanand that reuse is gone.
Cargo-Rail's local content-addressed store lives outside target/. Eligible compiler results remain available after
cargo clean and across target directories in the same physical source root. A different checkout uses an
independent cache session because Rust metadata can embed the source root; Cargo-Rail does not claim unsafe
cross-checkout portability.
On an eligible invocation, this sequence can still reuse exact compiler output:
cargo rail run --all --action build --explain
cargo clean
cargo rail run --all --action build --explainCargo-Rail does not restore an old target directory or manufacture Cargo freshness. Before a hit, it revalidates the relevant:
- Cargo, rustc, rustdoc, sysroot, backend, host, and wrapper identity;
- source and manifest inputs;
- dependency artifacts;
- observed environment reads;
- action and result identity; and
- exact stored output bytes.
The cache does not partition every compiler unit by the complete Cargo configuration or Cargo.lock. Within one
physical source root, output-neutral changes such as warning policy, job count, build or target directory, network
policy, registry settings, and unrelated lockfile entries can reuse a verified result. Rust flags, features,
dependency contents, target, linker, sysroot, and observed compiler inputs still change or reject reuse at their
owning boundary.
A matching lookup is not enough. Incomplete or unsupported evidence produces a named bypass and runs normal Cargo.
Fast when proven. Normal Cargo when not.
The retained v4 Linux and Windows x86-64 qualifications each measured one accepted same-host sample per lane:
| Host | Workload | Cargo-Rail warm | Native Cargo cold | sccache 0.16.0 |
Warm vs Cargo | Warm vs sccache |
|---|---|---|---|---|---|---|
| Linux | Check | 3.848 s | 9.866 s | 4.735 s | 61.0% faster | 18.7% faster |
| Linux | Release build | 6.055 s | 12.445 s | 7.918 s | 51.3% faster | 23.5% faster |
| Windows | Check | 9.744 s | 19.500 s | 12.847 s | 50.0% faster | 24.2% faster |
| Windows | Release build | 13.579 s | 23.150 s | 17.202 s | 41.3% faster | 21.1% faster |
Linux process-tree accounting measured 25.3% less CPU and 66.1% less peak RSS than sccache for check, and 20.4%
less CPU and 63.1% less peak RSS for release build. Windows retains wall-time comparisons but withholds specialist CPU
and RSS claims because the detached sccache server is outside that host's complete accounting boundary.
Each complete interleaved run accepted all 20 planned lane samples with zero rejections and zero false hits. On both hosts and workloads, the measured cold-publication premium was smaller than the saving from one warm reuse. These are bounded point measurements for one machine and fixture, not percentile, distribution, or universal workspace claims.
See Caching for the proof model, support matrix, raw methodology, and current qualification boundaries.
Most release automation tries to reconstruct intent after the code has already merged.
Cargo-Rail records it while the change is being reviewed:
cargo rail change add rail-core \
--bump minor \
--message "Added graph-aware release planning."The resulting .changes/*.md file lives beside the code change. Reviewers see the intended version bump and user-facing release note before merge—not weeks later when a release bot tries to infer them from commit messages.
CI can require release intent for every changed crate:
cargo rail change check --merge-base --requiredA release then carries that reviewed intent through the entire workflow:
code + reviewed .changes/*.md
│
▼
versions + changelogs
│
▼
exact release commit
│
▼
readiness on that SHA
│
▼
dependency-ordered publication
│
▼
registry observation + tags
│
▼
durable recovery state
Prepare a release pull request containing version and changelog updates:
cargo rail release run --all --bump auto --prAfter that exact release commit merges:
cargo rail release finalize --allCargo-Rail validates the release state, publishes crates in dependency order, observes registry results, and creates tags after publication.
Publication is authorized by the exact release commit—not by a moving branch head.
If publication is interrupted, the transaction is not left ambiguous:
cargo rail release status
cargo rail release resume <STATE>Changesets are not merely a nicer changelog format. They connect reviewed intent, workspace-aware versioning, publication order, the exact authorized SHA, and recoverable side effects.
Publishing a crate from a private monorepo usually creates another synchronization system—and eventually another source of truth.
Cargo-Rail keeps the split repository tied to its monorepo origin.
split extracts the relevant Git history and rewrites workspace-relative manifests:
cargo rail split run my-crate --check
cargo rail split run my-cratesync maps later commits in either direction:
cargo rail sync my-crate --to-remote
cargo rail sync my-crate --from-remoteInbound changes arrive on review branches. Synchronization uses Git's three-way merge, and manual conflicts are recorded in resumable receipts.
This is Cargo-aware crate synchronization, not a general-purpose repository-transformation language.
Cargo-Rail removes work in the order it appears:
unify
→ removes graph waste, hidden coupling, background resource consumption
plan
→ removes unaffected actions
package scope
→ removes unaffected crates inside selected actions
verified reuse
→ removes compiler invocations from the work that remains
These optimizations compound because they derive from the same captured source tree and resolved Cargo graph. The context is passed around... it's not re-computed.
Independent tools cannot compound as effectively: each optimization is bounded by its own approximation of the workspace.
Cargo-Rail treats speed as conditional and side effects as transactions:
- Plan before effect. Checks, explanations, schemas, and dry runs expose decisions before execution or mutation.
- Widen instead of undertesting. Incomplete planning evidence selects more work rather than silently excluding required work.
- Run cold instead of trusting weak cache evidence. Unsupported or incomplete reuse cases execute normal Cargo.
- Revalidate before mutation. Snapshot-bound commands confirm their assumptions immediately before writing, publishing, or synchronizing.
- Preserve user-owned configuration. Manifest and configuration edits are lossless outside fields owned by the operation.
- Record recovery state. Backups, plans, receipts, and durable release or sync state remain available where recovery requires them.
- Keep execution explicit. Repository actions are validated direct-process argument vectors, not an embedded shell language.
Fast paths are used only when their proof boundary holds.
Each workflow is independently adoptable:
- Observe with
cargo rail plan --merge-base --explain. - Compare with
cargo rail run --dry-run --print-cmd. - Delegate affected scope to existing jobs.
- Enforce read-only dependency and changeset checks.
- Apply graph repairs, release effects, or repository synchronization after the team trusts their plans and recovery boundaries.
Adopt a workflow when it deletes a second source of truth. Do not adopt it merely because Cargo-Rail implements it.
cargo install cargo-rail --lockedOr install a pre-built binary:
cargo binstall cargo-railPre-built archives, SHA-256 checksums, and signed provenance are published with GitHub Releases.
The current MSRV is published in
Cargo.toml.
- Planning and execution
- Configuration reference
- Command reference
- Architecture
- Caching
- Benchmarking
- Troubleshooting and recovery
- Migrate from cargo-hakari
- Migrate from git-cliff or release-plz
- Examples
Cargo-Rail is licensed under MIT.