No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-09 08:22:19 +02:00
examples feat: init 2026-09-09 08:22:19 +02:00
src feat: init 2026-09-09 08:22:19 +02:00
.gitignore feat: init 2026-09-09 08:22:19 +02:00
Cargo.lock feat: init 2026-09-09 08:22:19 +02:00
Cargo.toml feat: init 2026-09-09 08:22:19 +02:00
LICENSE-MIT feat: init 2026-09-09 08:22:19 +02:00
README.md feat: init 2026-09-09 08:22:19 +02:00

cargo-overrides

Experimental npm-style transitive dependency overrides for Cargo.

Cargo intentionally will not unify SemVer-incompatible requirements. This is especially noticeable for pre-1.0 crates, where 0.7 and 0.8 are incompatible ranges. cargo-overrides gives the workspace owner an escape hatch when they have verified that the newer version is actually source-compatible.

What it does

Given a graph like:

app
├── parent-a -> foo ^0.7
├── parent-b -> foo ^0.8
└── parent-c -> foo ^0.8

and:

# Cargo.overrides.toml
[overrides]
foo = "0.8.5"

cargo-overrides:

  1. runs cargo metadata;
  2. finds crates.io parent crates that declare a crates.io dependency on foo;
  3. copies those parents into target/cargo-overrides/shadow/;
  4. rewrites those dependency requirements to exactly =0.8.5 (including already-compatible ranges, so the requested version is pinned);
  5. generates a Cargo config with [patch.crates-io] entries pointing at the shadow crates;
  6. runs cargo metadata with that config to resolve/update the lockfile and verifies the requested crates.io version converged;
  7. runs the requested Cargo command with cargo --config <generated-config> ....

Cargo still performs dependency resolution and writes Cargo.lock. The tool does not manually forge lockfile entries.

Install

cargo install --path .

Then, from a Cargo workspace:

cargo overrides list
cargo overrides add foo@0.8.5
cargo overrides prepare
cargo overrides check
cargo overrides lock
cargo overrides exec build --release
cargo overrides exec test --all-features

You can also edit the file directly:

[overrides]
foo = "0.8.5"
bar = "0.12.3"

Important behavior

The override is intentionally stronger than Cargo's normal resolver: a dependency declaration such as:

foo = "0.7"

inside a crates.io parent can become:

foo = "=0.8.5"

in the generated shadow copy.

That may fail to compile or, worse, compile with unintended behavior. The root project is taking responsibility for violating the parent's declared compatibility range. Run tests.

Current MVP limitations

  • Only exact target versions are accepted (foo@0.8.5), not ranges.
  • Only crates.io parent packages are shadow-patched.
  • If a workspace member itself declares the incompatible requirement, edit that workspace manifest directly.
  • Git/alternate-registry parent patching is not implemented yet.
  • The generated shadow directory is disposable and lives under target/cargo-overrides.
  • Builds that rely on these overrides must be invoked through cargo overrides ... (or use the generated Cargo config themselves). A lockfile alone cannot encode "ignore the parent's declared version requirement".

Why not edit Cargo.lock directly?

Cargo.lock describes a resolved graph. The incompatible requirement lives in the parent package's Cargo.toml. Forging a lockfile cannot make that requirement disappear; Cargo will validate/re-resolve the graph. Shadow-patching the parent manifest changes the input to the resolver, after which Cargo can generate a legitimate lockfile.

Files

Cargo.overrides.toml            # commit this
target/cargo-overrides/         # generated, do not commit
Cargo.lock                      # generated by Cargo as usual

Safety / CI suggestion

A useful CI sequence is:

cargo overrides check -- --all-targets --all-features
cargo overrides exec test --all-features

Treat an override as temporary technical debt. Prefer upgrading or upstreaming a relaxed dependency requirement when possible.