Detect unused, outdated, and many-major-versions-behind dependencies. Wraps cargo-udeps + cargo-outdated, emits a structured verdict.
dev-* verification collection.Also available as the
deps feature of the dev-tools umbrella crate — one dependency, every verification layer.
dev-deps answers two questions about your dependency tree:
- Are any declared dependencies actually unused?
- Are any outdated, and by how many major versions?
It wraps cargo-udeps and
cargo-outdated and emits
findings as a dev-report::Report so AI
agents and CI gates can act on them programmatically.
[dependencies]
dev-deps = "0.9"One-time tool install:
cargo install cargo-udeps cargo-outdated
rustup toolchain install nightly # cargo-udeps requires nightlyDrive it from code:
use dev_deps::{DepCheck, DepScope};
let check = DepCheck::new("my-crate", "0.1.0").scope(DepScope::All);
let result = check.execute()?;
let report = result.into_report();
println!("{}", report.to_json()?);
# Ok::<(), Box<dyn std::error::Error>>(())| Scope | What it runs |
|---|---|
DepScope::Unused |
cargo +nightly udeps --output json only. |
DepScope::Outdated |
cargo outdated --format json only. |
DepScope::All |
Both. |
| Finding | dev-report::Severity |
|---|---|
| Unused dependency | Warning |
| Outdated, 0–1 major behind | Info |
| Outdated, 2+ majors behind | Warning |
Outdated, ≥ escalate_at_majors behind |
Error (failing) |
By default, every finding is a Warn-verdict check — dependency
health is advisory, not blocking. Call .escalate_at_majors(n) on the
builder to make findings at least n majors behind produce a failing
CheckResult instead.
use dev_deps::{DepCheck, DepScope};
use dev_report::Severity;
let check = DepCheck::new("my-crate", "0.1.0")
.scope(DepScope::All)
.workspace() // pass --workspace to both tools
.exclude("vendored-crate") // skip a whole crate
.allow("legacy-shim") // skip a single advisory ID / crate name
.allow_all(["a", "b"])
.severity_threshold(Severity::Warning) // drop Info findings
.escalate_at_majors(3); // fail when 3+ majors behind
let _result = check.execute()?;
# Ok::<(), Box<dyn std::error::Error>>(())DepProducer plugs the check into a multi-producer pipeline driven
by dev-tools:
use dev_deps::{DepCheck, DepProducer, DepScope};
use dev_report::Producer;
let producer = DepProducer::new(
DepCheck::new("my-crate", "0.1.0").scope(DepScope::All),
);
let report = producer.produce();
println!("{}", report.to_json().unwrap());Subprocess failures map to a single failing CheckResult named
deps::health with Severity::Critical — the pipeline keeps running.
DepResult, UnusedDep, OutdatedDep, DepScope, and DepKind
are all serde-derived. JSON output uses snake_case field names
and omits optional fields when they are None:
{
"name": "my-crate",
"version": "0.1.0",
"scope": "all",
"unused": [
{ "crate_name": "legacy", "kind": "development" }
],
"outdated": [
{
"crate_name": "serde",
"current": "1.0.0",
"latest": "2.0.0",
"major_behind": 1,
"kind": "normal"
}
]
}| File | What it shows |
|---|---|
examples/basic.rs |
Full check (All scope); graceful tool-missing handling. |
examples/unused_only.rs |
Unused scope only. |
examples/outdated_only.rs |
Outdated scope only. |
examples/producer.rs |
DepProducer (gated by DEV_DEPS_EXAMPLE_RUN). |
Both tools must be installed:
cargo install cargo-udeps cargo-outdated
rustup toolchain install nightly # cargo-udeps requires nightlyThe crate detects absence of either tool and surfaces a typed
DepError variant rather than panicking.
Runtime dependency footprint: dev-report, serde, serde_json.
UnusedDep::kind was a String in 0.1.0; it is now a typed DepKind
enum. OutdatedDep also gained an optional kind field. If you
constructed these struct literals in 0.1.0, update:
# use dev_deps::{DepKind, OutdatedDep, UnusedDep};
let _unused = UnusedDep {
crate_name: "foo".into(),
kind: DepKind::Normal, // was: String
};
let _outdated = OutdatedDep {
crate_name: "bar".into(),
current: "1.0.0".into(),
latest: "2.0.0".into(),
major_behind: 1,
kind: Some(DepKind::Normal), // new in 0.9.0
};The constructor surface (DepCheck::new, DepScope variants,
DepResult::into_report) is unchanged.
dev-deps ships independently and is also re-exported by the
dev-tools umbrella crate as
the deps feature. Sister crates cover the other verification
dimensions:
dev-report— report schema everything emitsdev-fixtures— deterministic test fixturesdev-bench— performance and regression detectiondev-async— async runtime verificationdev-stress— stress and soak workloadsdev-chaos— fault injection and recovery testingdev-coverage— code coverage with regression gatesdev-security— CVE / license / banned-crate auditdev-ci— GitHub Actions workflow generatordev-fuzz— fuzz testing workflowdev-flaky— flaky-test detectiondev-mutate— mutation testing
v0.9.x is the pre-1.0 stabilization line. The API is feature-complete
for unused-dependency detection, outdated-version detection, major-lag
escalation, allow-listing, and severity gating. Production use is fine;
1.0 will pin the public API and the wire format.
1.85 — pinned in Cargo.toml via rust-version and verified by
the MSRV job in CI.
Apache-2.0. See LICENSE.
Copyright © 2026 James Gober.