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 checkis the linter;ruff formatis the formatter. They are separate commands. Running onlyruff checkwill not reformat your code.
[!TIP]
ruff check --select I --fixruns 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#
| Prefix | Source | Common rules |
|---|---|---|
E / W | pycodestyle | Whitespace, indentation |
F | pyflakes | Unused imports (F401), undefined names (F821) |
I | isort | Import ordering |
B | flake8-bugbear | Likely bugs and design issues |
UP | pyupgrade | Modernize Python syntax (UP007: Optional[X] β X | None) |
N | pep8-naming | Class/function naming conventions |
S | bandit | Security checks |
RUF | ruff-specific | ruffβs own rules |
Check which rules are enabled#
ruff rule F401 # explain a specific rule
ruff linter # list all available linters