skip to content

ruff β€” Fast Linter & Formatter

Lint and format Python code with ruff β€” a single Rust-powered tool that replaces flake8, isort, and black. Covers configuration, rule selection, and CI usage.

3 min read 11 snippets yesterday quick read

ruff β€” Fast Linter & Formatter#

What it is#

Ruff is a Rust-powered Python linter and formatter. It runs 10–100Γ— faster than the tools it replaces and implements rules from flake8, isort, pyupgrade, pydocstyle, and many more in one binary. For new projects, ruff replaces black, flake8, isort, and pyupgrade.

Install#

pip install ruff

Quick example β€” check and auto-fix#

# myfile.py (intentionally messy)
import os
import sys

x=1
y = x+1
ruff check myfile.py

Output:

myfile.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 fixable with the `--fix` option.
ruff check --fix myfile.py
ruff format myfile.py

Output:

Fixed 1 error.
1 file reformatted

When / why to use it#

  • New projects: use ruff instead of black + flake8 + isort separately.
  • Existing projects: ruff is a drop-in replacement; configuration is near-identical to flake8/black.
  • CI pipelines: its speed (milliseconds for large codebases) makes it practical even in tight pipelines.

Common pitfalls#

[!WARNING] ruff format vs ruff check β€” ruff check is the linter; ruff format is the formatter. They are separate commands. Running only ruff check will not reformat your code.

[!TIP] ruff check --select I --fix runs only isort-style import sorting. Useful when migrating a codebase incrementally.

Richer example β€” pyproject.toml configuration#

[tool.ruff]
line-length = 88
target-version = "py312"
src = ["src", "tests"]

[tool.ruff.lint]
# Rule sets: E/W=pycodestyle, F=pyflakes, I=isort, B=bugbear, UP=pyupgrade, N=naming
select = ["E", "F", "I", "B", "UP", "N"]
ignore = ["E501"]        # let the formatter handle line length

# Auto-fix isort violations; other rules require --fix explicitly
fixable = ["I", "F401"]

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"]   # allow assert in tests

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true
ruff check --fix src/
ruff format src/

Output:

Found 3 errors (3 fixed, 0 remaining).
2 files reformatted, 8 files left unchanged

Using ruff in CI (GitHub Actions)#

# .github/workflows/lint.yml
- name: Lint with ruff
  run: |
    pip install ruff
    ruff check .
    ruff format --check .

ruff format --check exits non-zero if any file would be reformatted β€” safe for CI without modifying files.

Key rule prefixes#

PrefixSourceCommon rules
E / WpycodestyleWhitespace, indentation
FpyflakesUnused imports (F401), undefined names (F821)
IisortImport ordering
Bflake8-bugbearLikely bugs and design issues
UPpyupgradeModernize Python syntax (UP007: Optional[X] β†’ X | None)
Npep8-namingClass/function naming conventions
SbanditSecurity checks
RUFruff-specificruff’s own rules

Check which rules are enabled#

ruff rule F401       # explain a specific rule
ruff linter          # list all available linters