Clippy
Clippy is Rust's linter for correctness, performance, and idiomatic code. Run it on every PR with -D warnings to treat lints as errors.
Recipe
cargo clippy --workspace --all-targets -- -D warnings[lints.clippy]
enum_glob_use = "deny"When to reach for this: Always in CI; locally before pushing Rust changes.
Working Example
# Local
cargo clippy --all-targets -- -W clippy::pedantic
# CI (strict)
cargo clippy --workspace --all-targets --all-features -- -D warnings// clippy catches:
let v = vec![1, 2, 3];
let x = v.iter().cloned().collect::<Vec<_>>(); // use .copied() for Copy typesWhat this demonstrates:
--all-targetsincludes tests and benches-D warningspromotes warnings to errors- Manifest
[lints.clippy]sets default levels (Rust 1.74+) - Pedantic lints are opt-in for stricter teams
Deep Dive
Lint Categories
| Group | Examples |
|---|---|
| correctness | almost certainly bugs |
| suspicious | likely mistakes |
| style | idiomatic Rust |
| perf | unnecessary alloc/clone |
| pedantic | noisy but educational |
Allowing Exceptions
#[allow(clippy::too_many_arguments)]
fn legacy_api(...) { }
// prefer with reason:
#[allow(clippy::cast_possible_truncation)] // protocol defines u8 wire format- File-level:
#![allow(...)]at crate root sparingly - Prefer fixing over mass
allow
Gotchas
- Clippy without tests - test-only issues missed. Fix:
--all-targets. - Feature-gated dead code warnings - cfg-specific false positives. Fix:
cargo clippy --all-featuresjob. - Blanket allows - hides real bugs. Fix: per-line
allowwith comment. - Old clippy on new Rust - stale suggestions. Fix: match CI toolchain 1.97.0.
- Ignoring perf lints - death by a thousand clones. Fix: treat
clippy::redundant_cloneseriously in hot paths.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
rustc lints only | Minimal setup | Missing high-value clippy checks |
cargo-deny | Licenses/advisories | Replacing clippy style/correctness |
| Manual review | Never alone | Complement to clippy |
FAQs
clippy vs rustc lints?
Clippy is additional passes; both run via cargo clippy.
How fix cargo clippy noise in deps?
You cannot fix dep code; -A clippy::lint_name at crate root only for unfixable third-party macro expansions.
Should pedantic be default?
Usually no for large codebases; enable for new crates or incremental ratchet.
clippy on MSRV?
Run clippy on MSRV toolchain in CI matrix to catch unsupported APIs.
How auto-fix?
Some lints support cargo clippy --fix --allow-dirty - review diff carefully.
Workspace clippy?
Single command at root with --workspace shares target dir cache.
clippy in build.rs?
--all-targets includes build scripts; fix or allow explicitly.
Too many arguments lint?
Refactor to builder struct or config struct; allow only for generated/FFI bindings.
Does clippy slow CI?
Cached target/ helps; run after fmt; parallel with tests if runners allow.
Manifest [lints] vs attributes?
Prefer [lints.clippy] in Cargo.toml for crate-wide policy; line allows for exceptions.
Related
- rustfmt - formatting
- Configuring Clippy - clippy.toml
- Lint Levels & Attributes - allow/deny
- Linting in CI - enforcement
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.