Ruff Cheatsheet

A visual guide to Ruff covering check, fix, and format, selecting and ignoring rule codes, configuring via pyproject.toml, per-file ignores and noqa, the rule-code categories, and editor plus pre-commit integration.

python
ruff
cheatsheet
Author

James Balamuta

Published

August 7, 2026

Ruff is the extremely fast Python linter and formatter from Astral, written in Rust, where one binary replaces Flake8, isort, pydocstyle, pyupgrade, autoflake, and Black. It is a command-line tool rather than an importable library, so this sheet centers on subcommands, flags, rule codes, and pyproject.toml config instead of a Python API. The recurring mental model in every panel is one picture: a stack of .py files flows along a gray arrow through the lime ruff engine and comes out as either a green “All checks passed” badge, a red violation list (each row CODE message file:line), or a blue diff of applied fixes. Where this looks like the uv sheet, the pairing is the point: uv installs and runs your project, ruff lints and formats it. Ruff is a standalone binary, so there is no import line; each panel shows the bare ruff ... form, and the series-recommended way to drive it is through uv with uv run ruff check inside a project or uvx ruff check to run it ephemerally with no install.

Complete Ruff cheatsheet (light mode): eight panels covering ruff check, applying safe fixes, the formatter, selecting and ignoring rule codes, configuring via pyproject.toml, suppressing with noqa and per-file ignores, the rule-code categories, and editor plus pre-commit integration.

Complete Ruff cheatsheet (dark mode): eight panels covering ruff check, applying safe fixes, the formatter, selecting and ignoring rule codes, configuring via pyproject.toml, suppressing with noqa and per-file ignores, the rule-code categories, and editor plus pre-commit integration.

Download the full cheatsheet

All eight panels in a single, printable SVG.

Light SVG Dark SVG

Lint with ruff check

ruff check scans your Python (and notebooks) and prints each violation as CODE message with the offending file:line, then exits non-zero if anything is found, which is exactly what you want in CI. It is fast enough to run on the whole repo on every keystroke, so reach for --watch while editing, --statistics to see which rules dominate, and --output-format=github (or gitlab, junit, json) to feed other tools.

Ruff check panel: lint the whole project, lint specific paths, a clean run badge, per-rule statistics, watch mode, and picking the output format.

ruff check scans your code and lists violations, fast.

Ruff check panel: lint the whole project, lint specific paths, a clean run badge, per-rule statistics, watch mode, and picking the output format.

ruff check scans your code and lists violations, fast.
ruff check                          # lint the whole project
ruff check src/ tests/              # lint specific paths only
ruff check                          # clean run -> "All checks passed!"
ruff check --statistics             # count violations per rule
ruff check --watch                  # re-lint on every save
ruff check --output-format=github   # full|concise|json|github|gitlab|junit
# via uv: uv run ruff check

See The linter. Use the explicit ruff check <path> subcommand; the legacy top-level ruff <path> form is deprecated.

Fix with ruff check –fix

Many violations carry an automatic fix, and --fix rewrites your files to resolve every safe one in a single pass, reporting how many were fixed and how many remain. Preview first with --diff, see exactly what changed with --show-fixes, and only reach for --unsafe-fixes when you have read the diff, since those may change the meaning of your code rather than just its form.

Ruff fix panel: apply all safe fixes, preview without writing, list what got fixed, include unsafe fixes, fix-only mode, and restrict which rules may fix.

Apply the safe fixes automatically; opt in to the rest.

Ruff fix panel: apply all safe fixes, preview without writing, list what got fixed, include unsafe fixes, fix-only mode, and restrict which rules may fix.

Apply the safe fixes automatically; opt in to the rest.
ruff check --fix                    # apply all safe fixes
ruff check --diff                   # preview fixes, write nothing
ruff check --fix --show-fixes       # list each fix applied
ruff check --fix --unsafe-fixes     # also apply fixes that may change intent
ruff check --fix-only               # apply fixes, do not report leftovers
ruff check --fix --fixable I        # restrict which rules may fix

See Fixes. Read the diff before --unsafe-fixes; unsafe fixes can change behavior, not just style.

Format with ruff format

ruff format is a Black-compatible formatter built into the same binary, so one tool both lints and formats with no second dependency to install or pin. Use --check (and --diff) in CI to fail when code is not formatted, and remember the division of labor: the formatter handles whitespace, quotes, and line wrapping, while import sorting is the I lint rule applied with ruff check --select I --fix.

Ruff format panel: format the project in place, check formatting without writes, show the formatting diff, format specific files, and sort imports in a separate pass.

A Black-compatible formatter built into the same binary.

Ruff format panel: format the project in place, check formatting without writes, show the formatting diff, format specific files, and sort imports in a separate pass.

A Black-compatible formatter built into the same binary.
ruff format                         # format files in place
ruff format --check                 # fail CI if any file is unformatted
ruff format --diff                  # show what formatting would change
ruff format app.py src/             # format specific files
ruff check --select I --fix         # sort imports (format does NOT sort)
ruff format                         # then format whitespace and quotes

See The formatter. ruff format does not sort imports; run the I rule with ruff check --select I --fix for that.

Select and Ignore Rules

Ruff decides which of its 800-plus rules run from their letter-prefixed codes: --select sets the active set, --extend-select adds to whatever is already configured, and --ignore switches individual rules off. --select ALL turns on everything (great for discovery, too noisy to keep), --preview opts into unstable rules, and --unfixable lets a rule report without auto-fixing.

Ruff select and ignore panel: choose exactly which rules run, add to the default set, silence one rule, enable everything then trim, turn on preview rules, and mark a rule unfixable.

Turn rule families on and off by their codes.

Ruff select and ignore panel: choose exactly which rules run, add to the default set, silence one rule, enable everything then trim, turn on preview rules, and mark a rule unfixable.

Turn rule families on and off by their codes.
ruff check --select E,F,I,UP,B,SIM  # choose exactly which rules run
ruff check --extend-select B,SIM    # add to the configured set
ruff check --ignore E501            # silence one rule
ruff check --select ALL             # everything (discovery only, too noisy)
ruff check --preview                # opt into unstable rules and fixes
ruff check --fix --unfixable F401   # report F401 but block its auto-fix

See Rule selection. Codes are letter-prefixed by source linter, for example F, E, I, UP, B, SIM.

Configure with pyproject.toml

Put the flags you would otherwise retype into [tool.ruff] (project-wide options like line-length and target-version) and [tool.ruff.lint] (select, ignore), with sub-tables such as [tool.ruff.lint.isort] and [tool.ruff.format] for finer control. Any project can use a standalone ruff.toml instead (same keys, without the [tool.ruff] prefix), and ruff discovers the nearest config by walking up from each file.

Ruff config panel: set the line length, pin the target Python version, select and ignore rules in config, configure import sorting, set formatter options, and use a standalone ruff.toml.

Persist settings under [tool.ruff] so the team shares them.

Ruff config panel: set the line length, pin the target Python version, select and ignore rules in config, configure import sorting, set formatter options, and use a standalone ruff.toml.

Persist settings under [tool.ruff] so the team shares them.
[tool.ruff]
line-length = 100
target-version = "py313"

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]   # active rules (lint table, not top level)
ignore = ["E501"]                     # let the formatter own line length

[tool.ruff.lint.isort]
known-first-party = ["myapp"]         # group your code separately

[tool.ruff.format]
quote-style = "double"                # normalize to double quotes

See Configuring Ruff. select/ignore live under [tool.ruff.lint]; the old top-level keys are deprecated and warn.

Suppress with noqa and per-file ignores

When a rule is right almost everywhere, suppress the exceptions rather than disabling it: add # noqa: F401 (a specific code) or a bare # noqa (everything on the line) inline, or list per-file-ignores globs in config for whole categories of files such as tests. ruff check --add-noqa retro-fits suppression comments onto an existing codebase, --ignore-noqa audits what those comments are hiding, and ruff rule F401 explains any code in full.

Ruff suppress panel: ignore a code on one line, blanket-ignore a whole line, ignore rules for a path glob, auto-insert noqa, audit by ignoring all noqa, and explain a code.

Carve out exceptions without disabling a rule everywhere.

Ruff suppress panel: ignore a code on one line, blanket-ignore a whole line, ignore rules for a path glob, auto-insert noqa, audit by ignoring all noqa, and explain a code.

Carve out exceptions without disabling a rule everywhere.
import os  # noqa: F401              # ignore one specific code on this line
weird_code()  # noqa                # blanket-ignore the line (use sparingly)

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]            # re-exports are fine here
"tests/**" = ["S101"]              # assert is expected in tests
# ruff check --add-noqa             # insert # noqa on failing lines
# ruff check --ignore-noqa          # audit what those comments hide
# ruff rule F401                    # explain a rule code in full

See Error suppression. # noqa: F401 targets one code; a bare # noqa silences every rule on the line.

Rule-code Categories

Every rule code starts with a short prefix naming the upstream linter it came from: F is Pyflakes (real correctness bugs, keep it on always), E/W are pycodestyle style, I is isort import ordering, UP is pyupgrade modernization, and B is flake8-bugbear’s likely-bug patterns. There are dozens more (SIM, N, S, C4, PT, RUF, and so on); ruff linter lists them all, and you build your project’s rule set by combining the prefixes you trust.

Ruff rule-code categories panel: Pyflakes correctness F, pycodestyle style E and W, isort import sorting I, pyupgrade modernization UP, flake8-bugbear likely bugs B, and flake8-simplify plus pep8-naming SIM and N.

800+ rules grouped by a short letter prefix per source linter.

Ruff rule-code categories panel: Pyflakes correctness F, pycodestyle style E and W, isort import sorting I, pyupgrade modernization UP, flake8-bugbear likely bugs B, and flake8-simplify plus pep8-naming SIM and N.

800+ rules grouped by a short letter prefix per source linter.
F           # Pyflakes: undefined names, unused imports/vars (always keep on)
E, W        # pycodestyle: whitespace, blank lines, E501 line length
I           # isort: import ordering and grouping
UP          # pyupgrade: Dict[str, int] -> dict[str, int] for your target
B           # flake8-bugbear: likely bugs, e.g. mutable default def f(x=[])
SIM, N      # flake8-simplify (collapse if/else) and pep8-naming
# ruff linter lists every prefix

See Rules reference. Run ruff linter to list every prefix; combine the families you trust into your project’s set.

Integrate with editors and pre-commit

Ruff ships a language server (ruff server) that editors use for live diagnostics and format-on-save, and an official astral-sh/ruff-pre-commit repo whose ruff-check and ruff-format hooks gate every commit. Drive it ephemerally with uvx ruff (no install), gate CI with ruff check --output-format=github plus ruff format --check, and pin one rev / version across editor, pre-commit, and CI so everyone runs the same rules.

Ruff integrate panel: run the editor language server, run ephemerally with uvx, add the pre-commit hooks, auto-fix in the commit hook, gate CI on lint and format, and pin the version everywhere.

Lint and format on save and on every commit.

Ruff integrate panel: run the editor language server, run ephemerally with uvx, add the pre-commit hooks, auto-fix in the commit hook, gate CI on lint and format, and pin the version everywhere.

Lint and format on save and on every commit.
# ruff server                          # editor language server (format on save)
# uvx ruff check                       # run ephemerally via uv, no install
repos:                                 # .pre-commit-config.yaml
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.14.10                      # pin one version: editor, hooks, CI
    hooks:
      - id: ruff-check
        args: [--fix]                  # auto-fix in the commit hook
      - id: ruff-format
# CI gate: ruff check --output-format=github  &&  ruff format --check

See Other integrations. The hook ids are ruff-check and ruff-format; the bare id: ruff is the older linter alias.

Quick Reference

Key Ruff commands.
Command What it does Area
ruff check Lint the project, list violations Check
ruff check src/ tests/ Lint specific paths Check
ruff check --watch Re-lint on every save Check
ruff check --statistics Count violations per rule Check
ruff check --fix Apply all safe fixes Fix
ruff check --diff Preview fixes, write nothing Fix
ruff check --fix --unsafe-fixes Also apply unsafe fixes Fix
ruff format Format files in place Format
ruff format --check Fail if any file is unformatted Format
ruff format --diff Show what formatting would change Format
ruff check --select E,F,I,UP,B Choose exactly which rules run Select
ruff check --extend-select B,SIM Add to the configured set Select
ruff check --ignore E501 Silence one rule Select
ruff check --add-noqa Insert # noqa on failing lines Suppress
ruff rule F401 Explain a rule code Suppress
ruff linter List every rule prefix Rules
ruff server Run the editor language server Integrate
uvx ruff check Run ruff ephemerally via uv Integrate
Frequently used Ruff flags.
Flag Meaning
--fix Apply safe automatic fixes
--unsafe-fixes Also apply fixes that may change intent
--fix-only Apply fixes, do not report leftovers
--diff Print a diff instead of writing files
--show-fixes Enumerate each fix applied
--select / --ignore Set / unset active rule codes
--extend-select Add rules on top of the config
--preview Enable unstable rules and fixes
--statistics Per-rule violation counts
--output-format full, concise, json, github, gitlab, junit, …
--target-version py38py314 syntax target
--watch Re-run on file changes
--add-noqa Insert suppression comments
--ignore-noqa Ignore existing # noqa comments
Common Ruff rule prefixes (ruff linter lists all).
Prefix Source linter Catches
F Pyflakes Real bugs: undefined names, unused imports/vars
E, W pycodestyle Style: whitespace, blank lines, E501 length
I isort Import ordering and grouping
UP pyupgrade Modernize syntax for your target version
B flake8-bugbear Likely-bug patterns (mutable defaults, …)
SIM flake8-simplify Simpler equivalent code
N pep8-naming Class / function / variable naming
S flake8-bandit Security anti-patterns
C4 flake8-comprehensions Better comprehensions
PT flake8-pytest-style Pytest conventions
D pydocstyle Docstring conventions
ANN flake8-annotations Missing type annotations
RUF Ruff Ruff-specific lints
ALL (meta) Every rule (discovery only, too noisy to keep)
Suppressing violations.
You want to Do this
Ignore one code on one line # noqa: F401 after the code
Ignore several codes on a line # noqa: F401, E501
Ignore everything on a line bare # noqa (use sparingly)
Ignore codes across a file glob [tool.ruff.lint.per-file-ignores] map
Disable a rule project-wide add it to ignore = [...] in config
Add suppressions to old code ruff check --add-noqa
See what # noqa hides ruff check --ignore-noqa

Appendix: Sample Code

The lint to fix to format loop

# 1. See what is wrong
ruff check

# 2. Apply every safe fix, and sort imports (the I rule)
ruff check --fix

# 3. Format whitespace, quotes, and line wrapping
ruff format

# In CI, make both gate the build (write nothing, fail loudly):
ruff check --output-format=github
ruff format --check

A practical pyproject.toml config

[tool.ruff]
line-length = 100
target-version = "py313"

[tool.ruff.lint]
# Pyflakes (F) + pycodestyle (E/W) + isort (I) + pyupgrade (UP)
# + bugbear (B) + simplify (SIM)
select = ["E", "F", "I", "UP", "B", "SIM"]
ignore = ["E501"]            # let the formatter own line length

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]    # re-exports are fine here
"tests/**" = ["S101"]       # assert is expected in tests

[tool.ruff.lint.isort]
known-first-party = ["myapp"]

[tool.ruff.format]
quote-style = "double"

Both ruff check and ruff format honor this file. For example line-length = 100 shows up under ruff check --show-settings as linter.line_length = 100, and E501 no longer fires.

Inline suppression that ruff itself can write

import os  # noqa: F401   (kept intentionally)

# Generate these automatically on an existing codebase:
#   ruff check --add-noqa
# Then audit what they hide:
#   ruff check --ignore-noqa

ruff check --add-noqa on a file with an unused import os rewrites the line to exactly import os # noqa: F401 and prints Added 1 noqa directive.

Pre-commit hooks (.pre-commit-config.yaml)

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.14.10
    hooks:
      # Lint, fixing what is safe and re-staging the result
      - id: ruff-check
        args: [--fix]
      # Then format
      - id: ruff-format

The two hook ids are ruff-check and ruff-format. Pin rev to the same ruff version your editor and CI use so nobody sees different results.

Behavior notes

  • ruff check is the entry point, not bare ruff. The legacy top-level ruff <path> form to lint is deprecated; always use the explicit ruff check <path> subcommand.
  • select / ignore live under [tool.ruff.lint]. The old top-level keys in [tool.ruff] are deprecated and emit a warning; nest them in the lint table.
  • The formatter does not sort imports. ruff format handles whitespace, quotes, and wrapping; import sorting is the I lint rule, applied with ruff check --select I --fix.
  • Safe fixes are automatic, unsafe fixes are opt-in. --fix applies only the safe fixes; read the --diff before adding --unsafe-fixes, since those can change behavior, not just style.
  • The pre-commit hook ids are ruff-check and ruff-format. The bare id: ruff hook is the older alias for the linter; prefer the explicit ruff-check.
  • Pin one version everywhere. Match the rev in .pre-commit-config.yaml, your editor extension, and CI to the same ruff version so nobody sees different results.

References

Ruff documentation (latest)

Project and related