# How to Suppress a Ruff Warning on One Line


[Ruff](https://pydevtools.com/handbook/reference/ruff.md) flags a line that cannot be fixed right now: a legacy call site, a deliberate exception, a pattern the rule cannot see the reason for. A `# noqa` comment silences that one rule on that one line, leaving every other line under enforcement.

## Read the Rule Code From Ruff's Output

Every diagnostic starts with the code to suppress. Run the linter and read it off the report:

```bash
uv run ruff check --output-format concise .
```

`uv run` executes the command inside the project's virtual environment, ensuring all dependencies are installed first.

```
app.py:5:12: SIM115 Use a context manager for opening files
Found 1 error.
```

`SIM115` is the code. The [Ruff rule codes explainer](https://pydevtools.com/handbook/explanation/what-do-ruff-rule-codes-mean.md) covers what the prefixes mean.

## Append the Code to the Offending Line

Put `# noqa: CODE` at the end of the line the diagnostic points at:

```python {filename="app.py"}
import json


def load(path):
    data = open(path).read()  # noqa: SIM115
    return json.loads(data)
```

Re-run the linter to confirm:

```bash
uv run ruff check --output-format concise .
```

```
All checks passed!
```

The comment has to sit on the same physical line as the violation. For a multi-line string, put it after the closing triple quote, where it applies to the whole string.

To silence more than one rule, separate the codes with commas: `# noqa: SIM115, E501`.

## Always Name the Code

A bare `# noqa` suppresses every rule on the line, including rules that start firing there later:

```python
data = open(path).read()  # noqa
```

That comment hides `SIM115` today and hides whatever else lands on the line tomorrow. The targeted form fails loudly instead: if `SIM115` stops firing, Ruff tells you the comment is dead.

## Let RUF100 Delete Stale Suppressions

Rewrite `load` to use a context manager and the suppression becomes dead weight:

```python {filename="app.py"}
def load(path):
    with open(path) as f:  # noqa: SIM115
        return json.loads(f.read())
```

`RUF100` (unused-noqa) is in Ruff's default rule set, so it catches that with no configuration:

```
app.py:5:28: RUF100 [*] Unused `noqa` directive (unused: `SIM115`)
Found 1 error.
[*] 1 fixable with the `--fix` option.
```

Ruff removes the comment itself:

```bash
uv run ruff check --fix .
```

```
Found 1 error (1 fixed, 0 remaining).
```

The `# noqa: SIM115` comment is gone from the file. Suppressions stay tied to violations that actually exist rather than accumulating as scar tissue.

## Freeze Existing Violations in Bulk

Turning on a new rule across an old codebase produces hundreds of diagnostics at once. `--add-noqa` writes the comments for you, so the rule can be enforced on new code starting today:

```bash
uv run ruff check --add-noqa .
```

```
Added 2 noqa directives.
```

Each violating line gains its own targeted comment:

```python {filename="legacy.py"}
import json


def save(path, obj):
    handle = open(path, "w")  # noqa: SIM115
    handle.write(json.dumps(obj))
```

Commit that as a separate change, then work the suppressions down over time. `RUF100` keeps score as each one becomes unnecessary.

## Choose Between noqa and Ruff's Native Comment

Ruff also accepts its own syntax, `# ruff: ignore[CODE]`, with `--add-ignore` as the bulk equivalent. Both forms suppress the same way and both are cleaned up by `RUF100`.

| | `# noqa: SIM115` | `# ruff: ignore[SIM115]` |
| --- | --- | --- |
| Understood by flake8 and its plugins | Yes | No |
| Behavior with no codes listed | Suppresses every rule on the line | Suppresses nothing |

Prefer `# noqa` while any flake8-based tooling still reads the file, and for the familiarity of a syntax the wider ecosystem already shares. The native form is the safer default in a Ruff-only codebase, because the degenerate case fails closed.

{{< callout type="info" >}}
For a contiguous region rather than one line, use range comments instead. See [how to disable Ruff rules for a block of code](https://pydevtools.com/handbook/how-to/how-to-disable-ruff-rules-for-a-block-of-code.md).
{{< /callout >}}

## Learn More

- [Ruff error suppression](https://docs.astral.sh/ruff/linter/#error-suppression)
- [RUF100: unused-noqa](https://docs.astral.sh/ruff/rules/unused-noqa/)
- [lint.per-file-ignores setting](https://docs.astral.sh/ruff/settings/#lint_per-file-ignores) suppresses a rule across whole paths rather than single lines
- [How to configure recommended Ruff defaults](https://pydevtools.com/handbook/how-to/how-to-configure-recommended-ruff-defaults.md)
