Rust’s ecosystem provides a rich set of Cargo subcommands designed to enforce quality, security, and compatibility guarantees in CI pipelines. These tools operate on different artifacts—source code, Cargo.lock, Cargo.toml, and compiled binaries—and address concerns that cargo test, cargo fmt, and cargo clippy do not cover.

Feature Combination Testing

cargo-hack

cargo-hack tests crates against different feature flag combinations, catching issues where specific features fail to compile or conflict with each other. The core flags are --each-feature (runs the command once per feature) and --feature-powerset (runs the command for every combination of features). The powerset approach is exponential in the number of features, so --exclude-features and --skip allow pruning infeasible combinations.

The --optional-deps flag treats optional dependencies as features, which matters because Cargo implicitly creates a feature for each optional dependency. The --no-dev-deps flag removes dev-dependencies before running, useful when testing library crates in isolation. Unlike --no-dev-deps, --remove-dev-deps permanently modifies Cargo.toml and does not restore it.

For MSRV (Minimum Supported Rust Version) verification, --rust-version reads the package.rust-version field from Cargo.toml and runs the command against that toolchain. The --version-range flag generalizes this to test across a range of Rust versions.

# Verify each feature compiles independently
cargo hack check --each-feature --no-dev-deps
 
# Test feature powerset excluding expensive combinations
cargo hack test --feature-powerset --exclude-features expensive,nightly
 
# MSRV verification
cargo hack check --rust-version --all-features

Dependency Graph Analysis

cargo-deny

cargo-deny is a policy enforcement tool that analyzes the dependency graph against rules defined in deny.toml. It runs four independent checks: licenses, bans, advisories, and sources.

The licenses check verifies that all transitive dependencies use licenses from an allow-list. This matters for corporate environments with legal constraints. The bans check blocks specific crates (or specific versions) and can also flag duplicate versions of the same crate in the dependency tree. The advisories check queries the RustSec database for known vulnerabilities—overlapping with cargo-audit but integrated into a single tool. The sources check ensures dependencies come from trusted origins (crates.io, specific Git organizations, or local paths).

# deny.toml
[licenses]
allow = ["MIT", "Apache-2.0", "BSD-3-Clause"]
confidence-threshold = 0.8
 
[bans]
multiple-versions = "warn"
deny = [
    { name = "openssl", wrappers = ["openssl-sys"] },
]
 
[advisories]
vulnerability = "deny"
unmaintained = "warn"

Running cargo deny check executes all configured checks; cargo deny check licenses runs only the license check.

cargo-audit

cargo-audit scans Cargo.lock for crates with known security vulnerabilities listed in the RustSec Advisory Database. Unlike cargo-deny, it is a single-purpose tool focused exclusively on security advisories.

Version 0.18 (September 2023) introduced two significant changes: it switched from OpenSSL to rustls for TLS, eliminating a common source of C dependency vulnerabilities, and it adopted the sparse crates.io index protocol for faster advisory fetching. As of early 2025, version 0.21.2 addresses CVE-2024-27308 and CVE-2025-22620—users should ensure they run an up-to-date version.

cargo audit
cargo audit --deny warnings  # fail CI on warnings too

Tip

If you already use cargo-deny with the advisories check enabled, cargo-audit is redundant. However, cargo-audit has a smaller dependency footprint and faster startup time for pipelines that only need vulnerability scanning.

Unused Dependency Detection

Two tools detect unused dependencies with different tradeoffs:

cargo-udeps compiles the project using unstable compiler flags (-Z save-analysis or similar) to determine which crates are actually linked. This approach is accurate but requires a nightly toolchain and incurs full compilation time. False positives can occur for dependencies used only in doc-tests or through procedural macros.

cargo +nightly udeps --all-targets

Configuration in Cargo.toml allows ignoring known false positives:

[package.metadata.cargo-udeps.ignore]
normal = ["some_macro_crate"]

cargo-machete uses regex scanning of source files instead of compilation. It runs in seconds even on large workspaces, making it suitable for pre-commit hooks or fast CI checks. The tradeoff is reduced accuracy—indirect usage through macros or re-exports produces false positives.

cargo machete
cargo machete --fix  # automatically remove detected unused deps

Warning

cargo-machete can incorrectly flag dependencies that are used via #[macro_use] or re-exported through another crate. Always verify suggestions before applying --fix.

Semantic Versioning Enforcement

cargo-semver-checks

cargo-semver-checks detects accidental breaking changes by comparing the public API of the current version against the previously published version. It works by generating rustdoc JSON output and querying it with a set of lints that encode SemVer rules.

As of late 2025, the tool includes 242 lints covering scenarios such as: removing public items, changing function signatures, modifying struct field visibility, altering #[must_use] attributes, and changing repr/alignment of types. The tool supports multiple rustdoc JSON format versions, maintaining compatibility across Rust releases.

cargo semver-checks check-release
cargo semver-checks check-release --baseline-version 1.2.0

The Rust project has accepted a goal to integrate cargo-semver-checks into cargo publish, which would automatically block publishes that introduce undeclared breaking changes. Cross-crate analysis (detecting breaks that span crate boundaries) is under active development.

Code Coverage

cargo-llvm-cov

cargo-llvm-cov wraps LLVM’s source-based coverage instrumentation (-C instrument-coverage). Unlike gcov-based approaches, LLVM source-based coverage provides accurate line, region, and branch coverage without runtime overhead artifacts. Branch coverage and doc-test coverage require a nightly toolchain.

# Generate HTML report
cargo llvm-cov test --html --open
 
# Generate lcov format for CI upload
cargo llvm-cov test --all-features --workspace --lcov --output-path lcov.info

Integration with Codecov or Coveralls in GitHub Actions:

- name: Generate coverage
  run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- uses: codecov/codecov-action@v5
  with:
    files: lcov.info
    fail_ci_if_error: true

The tool integrates with both cargo test and cargo nextest, passing through their respective flags.

Test Execution

cargo-nextest

cargo-nextest is a test runner that executes each test in its own process, unlike cargo test which runs tests as threads within shared test binaries. Process isolation prevents shared mutable state from causing flaky tests and allows reliable timeouts and retries per test.

Performance gains come from parallelizing across test binaries more aggressively and from architecture optimizations. Benchmarks show 1.5–3× speedups on large workspaces. The tool supports test partitioning for distributing tests across CI workers, JUnit XML output for CI dashboards, and configuration profiles for environment-specific settings.

cargo nextest run
cargo nextest run --retries 2  # retry failing tests
cargo nextest run -E 'test(regex_pattern)'  # filter by expression

Configuration lives in .config/nextest.toml:

[profile.ci]
retries = 2
fail-fast = false
 
[profile.ci.junit]
path = "target/nextest/ci/junit.xml"

Binary Size Analysis

cargo-bloat

cargo-bloat analyzes compiled binaries to identify which crates and functions contribute most to binary size. This is useful for embedded targets, WebAssembly, or any context where binary size matters.

cargo bloat --release --crates
cargo bloat --release -n 20  # top 20 functions by size

The tool requires release builds with debug info (debug = true in the release profile) to map symbols back to source locations.

CI Pipeline Composition

A comprehensive Rust CI pipeline typically layers these tools in order of execution speed:

  1. cargo fmt --check — instant, catches formatting drift
  2. cargo clippy -- -D warnings — fast, catches common mistakes
  3. cargo machete — seconds, catches obvious unused deps
  4. cargo deny check — seconds, enforces license/security policy
  5. cargo nextest run or cargo test — minutes, runs test suite
  6. cargo hack check --each-feature — minutes, verifies feature combinations
  7. cargo semver-checks — minutes, prevents accidental breaking changes
  8. cargo llvm-cov — minutes, generates coverage report
  9. cargo +nightly udeps — minutes, thorough unused dep check (optional, periodic)

Tools with overlapping functionality (cargo-audit vs cargo-deny advisories, cargo-machete vs cargo-udeps) can be selected based on accuracy/speed tradeoffs and whether other features of the broader tool are needed.