I've released cargo-rail v0.20.0 and cargo-rail-action v6.1.0.
I built Cargo-Rail because my Rust workspace had basically acquired a second build system. It was spread across Cargo plugins, path filters, cache scripts, release bots, changelog generators, and repo sync tooling. Each tool owned a partial model of the same codebase, and each one paid again to discover some version of:
What is in this workspace, what depends on what, and what must happen next?
That duplication was not free. It consumed resources on my dev machine, repeated work in CI, expanded the supply chain, and created several sources of truth that could drift apart.
Cargo-Rail captures one authoritative workspace view from Cargo, Git, config, the toolchain, and source state. Dependency coherence, affected work planning, verified compiler reuse, releases, and crate split/sync all derive from that view.
It does not replace Cargo, rustc, or nextest. It makes them do less... in some cases, FAR less.
In my own work, this has replaced roughly fifteen Cargo plugins and release utilities, reduced monthly CI spend by 65%, and let me maintain a handful of public OSS repos uniformly from one monorepo. Those are my results, though... not promises for every workspace/user, but they DO explain why I no longer see Cargo-Rail as another optional convenience plugin. It is the first tool I install for a Rust workspace and I really believe the larger Rust community would benefit from doing the same.
A single, coherent build graph.
The first optimization is not a faster compiler. It is giving the compiler less unnecessary or inconsistent work:
cargo rail unify --check --explain
cargo rail unify --backup
unify detects version drift, hidden feature coupling, undeclared features, unused dependency edges, workspace-inheritance drift, manifest ordering drift, and MSRV mismatches. Decisions that remove graph edges carry compiler evidence, and Cargo-Rail validates the resulting Cargo graph before applying lossless TOML edits.
I've tested the efficacy and accuracy of the 'unify' command across codebases like UV, Ruff, Tokio, TiKV, Helix, HelixDB, Meilisearch, and others... I have yet to find a failure that wasn't correct in failing. For example, a lot of these projects are getting by w/ inherited, but undeclared features... technically bugs of the Cargo architecture. Tokio needs an exclusion to get by, but it's accumulated years of dev cruft, too. I suppose one exclusion isn't bad - all things considered.
The result is one coherent dependency policy:
versions are unified where the workspace/config permits it;
dependencies and features are declared where they are actually used;
unused edges are removed only when the evidence is complete;
manifests are edited deterministically w/o discarding unrelated formatting or comments;
the workspace MSRV is explicit and checked; and
published packages retain their open-world feature surface unless configuration explicitly declares the workspace to be the complete consumer universe.
I can inspect every proposed decision before it writes anything. If I apply with a backup and disagree with the result, I can restore it:
cargo rail unify undo
This replaces separate dependency unifiers, unused-dependency scanners, feature auditors, manifest sorters, MSRV scripts, and workspace-hack maintenance. More importantly, those tools no longer reload and reinterpret the same workspace independently. It's just way less work for my dev machine and the CI runners. Those resources are better spent on actual work and/or quicker compilation.
Only run the work affected by an actual change.
Obviously, the fastest check, test, benchmark, or CI job is the one that never needed to start:
cargo rail plan --merge-base --explain
cargo rail run --merge-base --dry-run --print-cmd --explain
The planner maps changed files to their owning crates, walks affected dependents through Cargo's resolved graph, and selects the build, test, documentation, benchmark, infrastructure, and configured repository actions that remain.
This is not a directory-glob shortcut. A file-first plan, its scope contract, text and JSON output, GitHub projection, dry-run preview, and runner arguments all consume the same scope decision. The explanation shows why each surface and crate was selected.
The companion action exposes that decision to an existing workflow:
- uses: loadingalias/cargo-rail-action@v6
id: rail
with:
version: 0.20.0
cargo-rail-action exports affected surfaces and exact Cargo package arguments. It does not build, test, cache, release, or publish. Existing jobs remain the execution authority, so - critically - adopting affected planning does not require adopting another CI framework.
For my workloads, using this model locally and in CI reduced monthly CI spend by 65%. The saving came from removing irrelevant actions before trying to make the remaining actions faster.
A cache that survives cargo clean.
Cargo-Rail then removes compiler work from the actions that still need to run.
Its native cache is not a copied target/ directory. Reusable results live in a bounded content-addressed store outside target/, so cargo clean does not erase them. A compatible clean checkout can reuse results populated by another workspace root w/o restoring incremental state, forging Cargo fingerprints, or overriding Cargo's own freshness checks.
Before restoring a byte, Cargo-Rail revalidates the exact toolchain, source and observed reads, dependency artifacts, relevant environment, action and result identity, output tree, and stored blobs. Unsupported or incompletely observed compiler units run normally through Cargo and report a stable bypass reason... as they must.
That gives the cache a deliberately simple rule:
Fast when proven. Normal Cargo when not.
This is the latest feature and I'm really interested in how it can be improved. I hate the slow compilation times in Rust - especially as my core work is in a monorepo with 50+ crates and I've been in there for years. I am really looking for feedback here. I'm considering the next steps and I have some ideas. I'm also considering the ideal remote cache situation and how to design that without turning cargo-rail into a networking stack. I'm open to ideas; I've been thinking about opening a Discussion for users?
Tested across macOS, Linux, and Windows
Cache correctness, compiler observation, clean-root behavior, content-addressed storage, atomicity, cleanup, and filesystem boundaries are exercised across macOS, Linux, and Windows. The compatibility suite includes APFS, ext4, NTFS, Linux tmpfs, case-sensitive APFS, Windows NTFS VHDs, and Windows path behavior.
Performance qualification is a separate claim. The accepted scorecard currently contains 110 interleaved samples for each of macOS ARM64, Linux x86-64, and Linux ARM64, with ZERO false hits. Each sample starts with a clean target; warm-cache samples use distinct seed and consumer roots. The fixture includes registry and Git dependencies, build scripts, a proc macro, native code, workspace libraries, and a binary.
Warm cross-root p50 results against native Cargo are:
Host
Workload
Native Cargo
Cargo-Rail warm
Change
macOS ARM64
check
7.028 s
4.979 s
29.2% lower
macOS ARM64
release build
10.369 s
7.630 s
26.4% lower
Linux x86-64
check
5.841 s
3.430 s
41.3% lower
Linux x86-64
release build
9.224 s
5.547 s
39.9% lower
Linux ARM64
check
6.166 s
3.870 s
37.2% lower
Linux ARM64
release build
10.591 s
6.618 s
37.5% lower
Against sccache 0.16.0's local disk backend, Cargo-Rail won both macOS workloads and both Linux release builds. sccache led the Linux check workload by 8.7% on x86-64 and 0.7% on ARM64. The comparison includes the bad news because a cache benchmark without its losses is advertising, not evidence. Having said that, I'm looking for the next step here to address this.
Windows has been tested and benchmarked, but its current timing is intentionally not in the qualified scorecard. At the time, the bench contract was a mess because of an infra failure that I didn't have the time to address. I will get this handled soon.
Execution support, performance qualification, and permission to restore a native compiler result are independent. Cargo-Rail 0.20 graduates native reuse only for the exact macOS ARM64 Cargo/rustc 1.97.1 certificate and eligible library metadata/rlib units with CARGO_INCREMENTAL=0. Qualified Linux hosts still run Cargo normally until their exact capability certificates graduate. Existing sccache and custom wrappers are preserved; Cargo-Rail steps aside instead of double-caching.
Inspect the exact decision on a machine with:
cargo rail doctor native-cache --format json
The cache directory is configurable, and verified results are reusable across compatible clean roots. That already makes reuse between local checkouts and repeatable development environments valuable. I am now exploring the right remote-cache protocol for CI, SSH development, and local machines. I do not want to bolt a network transport onto an incomplete identity model; remote reuse must preserve the same fail-closed proof as local reuse.
The complete methodology, p95 results, cold-population cost, sccache comparison, bypasses, and rejected evidence are in the caching guide. The generated support matrix records what is executed, performance-qualified, and actually permitted to restore.
Release intent should survive the commit that introduced it (Rust Changesets)
A dep graph can derive dependent version bumps and publication order. It cannot decide whether a change is major, minor, or patch, or explain the change to a user.
Cargo-Rail records that human decision beside the code in reviewed .changes/*.md files:
cargo rail change add my-crate --bump minor --message "Added verified compiler-result reuse."
cargo rail change status
cargo rail change check --merge-base --required
Those entries connect a change to its intended audience, version impact, changelog entry, and release notes before the reason disappears into Git history. The result is release prose written for users rather than a reformatted commit log. This has made the 'Release Notes' for my current projects SO much better.
The release command combines reviewed intent with the resolved dependency graph:
cargo rail release run --all --bump auto --check
cargo rail release run --all --bump auto
For teams that review generated release changes first, Cargo-Rail also supports release preparation followed by finalization:
cargo rail release run --all --bump auto --pr
cargo rail release finalize --all
The workflow validates the exact release commit, generates versions and changelogs, publishes dependencies before dependents, waits until registry results become observable, creates tags last, and records durable state before remote effects. If a release is interrupted, cargo rail release status reports what happened and cargo rail release resume continues from that state without blindly repeating completed external operations.
That recovery behavior matters more than a happy-path one-command demo. Publication is irreversible; release tooling must know the difference between “not attempted,” “attempted but not observed,” and “confirmed.”
Split from a monorepo without adopting Copybara (or Java )
I maintain a few repos from one monorepo. I want the monorepo to remain the dev authority without turning each public repo into a generated code dump or adopting a Java service and transformation DSL.
Cargo-Rail's split/sync workflow is Cargo-aware:
cargo rail split init my-crate --dry-run
cargo rail split run my-crate --check
cargo rail split run my-crate
split extracts one or more configured crates into standalone repositories while preserving relevant Git history and rewriting workspace-relative manifests. Development can continue in the monorepo after the initial split.
Later changes can move in either direction:
cargo rail sync my-crate --check
cargo rail sync my-crate --to-remote
cargo rail sync my-crate --from-remote
sync maps commits between the monorepo and split repository, uses Git's three-way merge machinery, and creates inbound review branches. Automatic, ours, theirs, manual, and union conflict strategies are explicit. A manual conflict writes a receipt that can be resolved and resumed rather than abandoning the synchronization halfway through.
It is intentionally not a general-purpose repository transformation language. It solves the Rust monorepo-to-public-crate workflow with Cargo manifests, Git history, exact ownership, and resumable conflicts. Rust monorepos are, in my opinion, the best way to develop... but that's not always true for releases, or splitting a few crates into a new lib for the OSS community. This has helped keep my wires from crossing so many times.
No Java. No Copybara. No copy-and-pray shell script.
One binary also means a smaller supply-chain problem
Replacing the tool/plugins pile is not useful if the replacement quietly embeds the same pile.
Cargo-Rail implements these workflows in one Rust binary with a deliberately small direct dependency surface. It does not invoke the retired Cargo plugins behind the scenes. Production code forbids unsafe, release archives carry SHA-256 checksums and signed provenance, CI pins third-party actions, and unsupported cache or release states fail closed.
The dependency surface matters because Cargo-Rail sits at the bottom of development, CI, mutation, release, and publication workflows. A workspace engine is supply-chain infrastructure; treating its own supply chain as an afterthought would invalidate the design.
I'm currently using 16 core deps; most of which have been audited and/or are trusted crates from the Rust ecosystem. I'd love this to be a lower number, but it's not the trade I want to make here today.
The beginning of 'What I removed from my codebases/workspaces':
Depending on the repo, Cargo-Rail has replaced or made unnecessary:
cargo-hakari and workspace-hack maintenance;
cargo-hack;
cargo-msrv;
feature-declaration and inheritance auditors;
cargo-shear, cargo-machete, and cargo-udeps;
cargo-sort;
path-filter and affected-package scripts;
cargo-cache cleanup workflows;
cargo-release and release-plz;
git-cliff;
Copybara or custom split/sync automation; and
the glue required to make those independent models agree.
The value is not the length of that list. It is the compounding effect:
A coherent dep graph removes unnecessary work and hidden coupling.
Affected planning removes actions that do not need to run.
Verified caches remove compiler work from the actions that remain.
Reviewed change intent drives deterministic, resumable releases.
Split/sync preserves one development authority across public repositories.
All five operate on the same captured workspace instead of rebuilding competing models around it.
Try to break it!
cargo install cargo-rail
cargo rail plan --merge-base --explain
cargo rail unify --check --explain
Cargo-Rail: GitHub - loadingalias/cargo-rail: The Rust Workspace Engine: fewer tools, less work, faster builds, safer releases. · GitHub
Cargo-Rail 0.20.0: Release cargo-rail v0.20.0 · loadingalias/cargo-rail · GitHub
GitHub Action: GitHub - loadingalias/cargo-rail-action: Rail for GitHub Actions: affected Cargo scope without replacing your CI jobs. · GitHub
If the affected scope is wrong, a dependency decision lacks evidence, a cache restores an invalid result, a release cannot safely resume, or split/sync loses history or intent, that counterexample is more useful to me than another benchmark win.
2 posts - 1 participant
Read full topic
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Cargo-readme 3.4.0 released with Cargo workspace inheritance support | 0 | 18.41 | 27-07-2026 |
| 2 | My state lib PurrGress | 0 | 12.62 | 13-08-2026 |
| 3 | Tokcost — zero-dependency CLI for exact LLM token counts (hand-rolled BPE) | 0 | 12.74 | 02-08-2026 |
| 4 | Qhull_rayon v0.1.0 | 0 | 10.4 | 11-08-2026 |
| 5 | [Show] taetype: Pure Rust font engine with zero unsafe code | 0 | 10.19 | 27-07-2026 |
| 6 | Unsupported!() macro for compile errors when a code path is used | 0 | 8.18 | 13-08-2026 |
| 7 | Multicalc: Scientific computing for real-time embedded systems in no_std Rust | 0 | 14.36 | 10-08-2026 |
| 8 | FUI-RS: retained Rust UI for WebAssembly and native desktop without a WebView | 0 | 11.54 | 30-07-2026 |
| 9 | My second crate :D : Karatepe, a localisation library | 0 | 6.84 | 11-08-2026 |
| 10 | Sigid: a zero-dependency, no_std, three-layer unique ID generator | 0 | 14.69 | 11-08-2026 |