---
title: How to Configure Clippy Lints in Rust
summary: Configure Clippy lints by adding rules to Cargo.toml or using attributes in your Rust source code.
lang: en
slug: how-to-configure-clippy-lints-in-rust
published: 2026-04-17T12:05:42+00:00
updated: 2026-04-25T22:00:13+00:00
canonical: https://www.rustfaq.org/en/how-to-configure-clippy-lints-in-rust/
---

# How to Configure Clippy Lints in Rust



## When the compiler isn't enough

You're scanning a pull request. The logic works. The tests pass. But there's a `Vec::new()` followed immediately by `reserve()`. It's inefficient. You could comment it, but you've seen this pattern three times this week. You want the build to fail when someone writes it. That's where Clippy configuration comes in.

Clippy ships with hundreds of lints, but the defaults are conservative. They warn about obvious bugs and common mistakes. To enforce your team's style or catch subtle inefficiencies, you have to tune the lints. Configuration turns Clippy from a passive observer into an active guardian of your code quality.

## Clippy as a code review bot

Clippy acts as a second layer of analysis on top of `rustc`. The compiler checks for type safety and memory validity. Clippy checks for idiomatic code, performance traps, and logic errors that are technically valid but practically wrong.

Think of Clippy as a code review bot that reads the entire codebase. Lints are the checklist items. Some items are red flags that stop the review. Others are yellow flags that suggest a better way. Configuration is where you customize the checklist for your project. You decide which rules are mandatory, which are suggestions, and which don't apply to your domain.

## Lint levels and the `Cargo.toml` section

Every lint has a level. The level determines what happens when the lint triggers.

- `allow`: The lint is silenced. No warning, no error.
- `warn`: The lint prints a warning. Compilation continues.
- `deny`: The lint turns into a compilation error. The build fails.
- `forbid`: The lint is denied, and downstream code cannot override it with `allow`.

You set these levels in the `[lints]` section of `Cargo.toml`. This is the standard place for project-wide lint configuration.

```toml
[lints.clippy]
# Deny prevents compilation if this pattern is found.
approx_constant = "deny"

# Warn allows compilation but prints a message.
unused_self = "warn"

# Allow silences a lint that is too noisy for this project.
cast_precision_loss = "allow"
```

The `[lints.clippy]` table maps lint names to levels. The `clippy` key scopes these settings to Clippy. You can also configure `rust` lints in the same section using `[lints.rust]`.

Run `cargo clippy` to apply these rules. The tool reads `Cargo.toml`, merges the settings, and runs the analysis. If a lint hits `deny` or `forbid`, the build stops.

Treat `deny` as your quality gate. If a pattern is bad enough to break the build, set it to `deny`.

## Attributes for local control

`Cargo.toml` sets the baseline. Attributes in source code override the baseline for specific items. Attributes take precedence over `Cargo.toml`.

Use attributes when a lint is valid globally but wrong in a specific case. Or when you want to enforce a rule on a single function without affecting the rest of the crate.

```rust
/// This function intentionally uses a magic number for a hardware register.
#[allow(clippy::unreadable_literal)]
fn read_register() -> u32 {
    // The literal is obscure, but the hardware spec requires this exact value.
    0xDEADBEEF
}

/// This function must not be called with approximate constants.
#[deny(clippy::approx_constant)]
fn calculate_pi_area(radius: f64) -> f64 {
    // This will fail to compile if someone writes 3.1415 here.
    std::f64::consts::PI * radius * radius
}
```

Attributes apply to the item they decorate. `#[allow(...)]` on a function silences the lint inside that function. `#[deny(...)]` raises the level to error for that function, even if `Cargo.toml` says `warn`.

Convention aside: keep attributes close to the code they affect. Don't put `#[allow(...)]` at the crate root unless you have a compelling reason. Local overrides make it clear why the rule is broken.

Trust the attribute scope. If you silence a lint on a module, you silence it for every function in that module. That's often too broad.

## Workspace inheritance and groups

In a workspace, you don't want to repeat lint configuration in every crate. Use `[workspace.lints]` in the root `Cargo.toml` to define shared rules.

```toml
# Root Cargo.toml
[workspace.lints.clippy]
# Enable the pedantic group with warnings.
pedantic = { level = "warn", priority = -1 }

# Override specific lints that are too strict.
too_many_lines = "allow"
single_match = "allow"
```

Crate-level `Cargo.toml` files inherit from the workspace. They can override individual lints.

```toml
# Crate Cargo.toml
[lints]
workspace = true

[lints.clippy]
# This crate is a CLI tool. Long lines are acceptable in the help text.
too_many_lines = "deny"
```

The `workspace = true` line pulls in the workspace configuration. The crate can then tweak specific lints.

Clippy provides lint groups to enable many lints at once.

- `pedantic`: Lints that are generally good but might be too noisy for some projects.
- `nursery`: New lints that are still experimental.
- `restriction`: Lints that restrict valid code to enforce stricter standards.

Groups use a priority system. Lower priority numbers apply first. Higher priority numbers override lower ones. Setting `priority = -1` on a group ensures that individual lint overrides in the same table take effect.

Convention aside: `pedantic` is the standard starting point for libraries. It catches style issues that reviewers usually flag. Enable it with `warn`, then `allow` the ones that annoy you.

Use workspace lints to enforce consistency. If every crate has different rules, the configuration becomes noise.

## The `clippy.toml` configuration file

`Cargo.toml` handles lint levels. `clippy.toml` handles tool configuration. Some lints accept parameters. For example, `too_many_arguments` lets you set the threshold.

Create a `clippy.toml` file in the project root.

```toml
# clippy.toml
# Allow up to 12 arguments before the lint triggers.
too_many_arguments = 12

# Ignore specific files for the `module_name_repetitions` lint.
ignore-test-files = ["tests/integration.rs"]
```

Clippy reads `clippy.toml` automatically. The file supports workspace inheritance too. Put `clippy.toml` in the workspace root, and all crates use those settings.

Convention aside: keep `clippy.toml` small. Use it for thresholds and file ignores. Use `Cargo.toml` for lint levels. Mixing configuration types makes the setup harder to read.

Treat `clippy.toml` as the tuning dial. Adjust thresholds until the lints match your project's reality.

## Pitfalls and compiler errors

Lint configuration has traps. The most common is the unknown lint error.

If you typo a lint name, Clippy rejects it with `E0602` (unknown lint). The compiler doesn't know what you're trying to configure. Check the spelling. Clippy lints live in the `clippy::` namespace. In `Cargo.toml`, you can omit the `clippy::` prefix inside `[lints.clippy]`. In attributes, you must include it.

```rust
// This fails with E0602 because the prefix is missing.
#[allow(approx_constant)]
fn bad() {}

// This works.
#[allow(clippy::approx_constant)]
fn good() {}
```

Another trap is `forbid`. `forbid` prevents overrides. If you `forbid` a lint in a library crate, users of your crate cannot silence it. This can break downstream builds if the lint triggers in their code that calls your API.

Use `forbid` only for lints that must never be suppressed. Examples include lints that catch undefined behavior or security issues. For style lints, `deny` is usually enough. Users can `allow` a `deny` if they have a reason. They cannot `allow` a `forbid`.

Convention aside: libraries should avoid `forbid` on style lints. It forces your style on your users. That's a recipe for friction.

The `allow` trap is subtle. If you `allow` a lint everywhere, you lose the benefit of the lint. Use `allow` sparingly. Prefer `expect` for temporary suppressions.

`#[expect(clippy::lint)]` works like `allow`, but it warns if the lint is no longer triggered. This is useful when you suppress a lint for a known issue that might get fixed later. If the code changes and the lint stops firing, `expect` tells you that the suppression is dead weight.

Trust `expect`. It turns dead suppressions into warnings. You'll catch the moment your code improves.

## Decision matrix

Use `[lints]` in `Cargo.toml` for project-wide lint levels. Set `deny` for patterns that break the build. Set `warn` for suggestions. Set `allow` only when the lint is genuinely wrong for your code.

Use `[workspace.lints]` in the root `Cargo.toml` to share rules across crates. Inherit with `workspace = true` in child crates. Override specific lints per crate when needed.

Use `clippy.toml` for tool configuration. Set thresholds for lints like `too_many_arguments`. Configure file ignores. Keep this file separate from lint levels.

Use attributes for local overrides. Apply `#[allow(...)]` to specific functions or blocks where the lint is a false positive. Apply `#[deny(...)]` to enforce stricter rules on critical code.

Use `forbid` for mandatory safety lints. Reserve this for cases where suppression would hide a bug or security risk. Avoid `forbid` for style preferences.

Use `expect` instead of `allow` for temporary suppressions. It warns you when the lint is no longer relevant, keeping your configuration clean.

## Where to go next

- [How to Uninstall Rust Completely](/en/how-to-uninstall-rust-completely/)
- [How to Use cross for Easy Cross-Compilation](/en/how-to-use-cross-for-easy-cross-compilation/)
- [How to cross-compile with Cargo](/en/how-to-cross-compile-with-cargo/)