65. Ruff for Code Quality
Date: 2025-11-29Status
AcceptedCategory
Development & ToolingContext
Python code quality historically required multiple tools:- black: Code formatting
- isort: Import sorting
- flake8: Linting (style, errors)
- pylint: Deep static analysis
- pyupgrade: Python version upgrades
- autoflake: Remove unused imports
- Complex configuration across multiple files
- Slow execution (multiple passes over code)
- Conflicting rules between tools
- Version compatibility issues
Performance Comparison (large codebase, ~50k lines)
| Tool | Time | Rules |
|---|---|---|
| flake8 | ~15s | ~100 |
| pylint | ~45s | ~200 |
| black + isort | ~8s | formatting |
| ruff | ~0.5s | 800+ |
Decision
Use ruff (by Astral) as the single tool for linting, formatting, and import sorting.Key Reasons
- Speed: 10-100x faster than alternatives (written in Rust)
- All-in-one: Replaces black, isort, flake8, pyupgrade, autoflake
- 800+ Rules: Covers flake8, pylint, pyupgrade, bandit, and more
- Auto-fix: Most issues can be fixed automatically
- pyproject.toml: Single configuration file
- Active Development: Rapid iteration by Astral team
Configuration
Usage
Pre-commit Integration
Consequences
Positive
- Speed: Near-instant linting, even on large codebases
- Simplicity: One tool, one config file
- Consistency: Same rules across all developers
- Auto-fix: Most issues resolved automatically
- Modern Rules: Catches Python 3.11+ improvements
Negative
- New Tool: Team must learn ruff-specific configuration
- Less Mature: Some edge cases not covered by flake8/pylint
- Opinionated: Less flexibility than separate tools
Migration from Multiple Tools
Rule Categories
| Category | Prefix | Description |
|---|---|---|
| pycodestyle | E, W | PEP 8 style |
| pyflakes | F | Undefined names, unused imports |
| isort | I | Import sorting |
| flake8-bugbear | B | Likely bugs |
| flake8-comprehensions | C4 | Simplify comprehensions |
| pyupgrade | UP | Python version upgrades |
| pylint | PL | Deep analysis |
| ruff-specific | RUF | Ruff-only rules |
Alternatives Considered
black + isort + flake8
- Rejected: Slow, multiple configurations, version conflicts
- Three separate tools with overlapping concerns
pylint
- Rejected: Very slow, overly strict defaults
- Many false positives require extensive configuration
pyright/mypy (for linting)
- Considered: Type-based linting is powerful
- Kept alongside ruff: mypy for type checking, ruff for style/bugs
References
- Configuration:
pyproject.toml[tool.ruff] - Pre-commit:
.pre-commit-config.yaml - Related ADRs: ADR-0064, ADR-0062
- External: Ruff Documentation