π§ 1. What is Ruff and Why Use It
Ruff is a fast, all-in-one Python linter, formatter, and import sorter written in Rust.
It replaces multiple tools like Flake8, isort, Black, and pyupgrade, drastically speeding up development and CI pipelines.
βοΈ Key Benefits
| Feature | Ruff Advantage |
|---|---|
| π Speed | 10β100Γ faster than Flake8 or Pylint |
| π§° All-in-one | Linting + Formatting + Import Sorting |
| βοΈ Unified config | Simple setup via pyproject.toml
|
| π‘ Auto-fix | Many issues can be fixed automatically |
| π§ CI-friendly | Supports GitHub annotations |
π§± 2. Create a Lightweight Example Application
Letβs create a simple Python app: a small To-Do manager.
ποΈ Project structure
todo_app/
βββ app/
β βββ __init__.py
β βββ main.py
β βββ utils.py
βββ tests/
β βββ test_main.py
βββ pyproject.toml
βββ requirements.txt
βββ .github/
βββ workflows/
βββ lint.yml
π§° 3. Build the Example App
app/main.py
from app.utils import add_task, list_tasks
def main():
print("Welcome to the To-Do App")
add_task("Learn Ruff")
add_task("Integrate Ruff in CI")
print("Your Tasks:")
for task in list_tasks():
print(f"- {task}")
if __name__ == "__main__":
main()
app/utils.py
tasks = []
def add_task(task: str):
"""Add a task to the list."""
if not task:
raise ValueError("Task cannot be empty")
tasks.append(task)
def list_tasks():
"""Return all tasks."""
return tasks
tests/test_main.py
from app.utils import add_task, list_tasks
def test_add_task():
add_task("Task 1")
assert "Task 1" in list_tasks()
π¦ 4. Install Ruff
pip install ruff
Verify:
ruff --version
βοΈ 5. Configure Ruff with pyproject.toml
Hereβs a well-commented configuration file with real-world defaults and examples.
pyproject.toml
[tool.ruff]
# Maximum line length (similar to Blackβs default)
line-length = 88
# Specify Python version for compatibility
target-version = "py311"
# Select rulesets to enforce
# Common rule groups:
# E/F = Pycodestyle (errors & warnings)
# W = general warnings
# I = import sorting
# UP = pyupgrade rules (modernize code)
# N = naming conventions
select = ["E", "F", "W", "I", "UP"]
# Ignore specific rule codes if desired
ignore = [
"E501", # ignore line length errors (if you rely on Black)
]
# Exclude certain paths (like virtualenvs or migrations)
exclude = ["venv", "build", "__pycache__", "migrations"]
# Show fixes when applying --fix
show-fixes = true
# Respect .gitignore patterns
respect-gitignore = true
# Auto-detect per-file ignores if necessary
per-file-ignores = { "tests/test_*.py" = ["S101"] }
# Enable incremental mode (optional, speeds up re-runs)
cache-dir = ".ruff_cache"
[tool.ruff.lint.isort]
# Sort imports intelligently
known-first-party = ["app"]
combine-as-imports = true
π§© 6. Useful Ruff Commands
Hereβs a table of common Ruff commands with explanations and when to use them:
| Command | Description | Use Case |
|---|---|---|
ruff check . |
Run all lint checks | β Recommended default |
ruff check . --fix |
Auto-fix lint errors | Use locally/pre-commit |
ruff format . |
Format all Python files | Code beautification |
ruff format --check . |
Check if code is properly formatted | Use in CI |
ruff rule <CODE> |
Get details for a specific rule (e.g., ruff rule E501) |
Learn rules |
ruff --explain <CODE> |
Explain why a rule triggered | Debugging |
ruff --help |
Show CLI options | General help |
Recommended CI Command:
ruff check .
It ensures linting consistency, and when combined withruff format --check ., it gives both lint + format verification without auto-fixing in CI.
π§° 7. (Optional) Pre-commit Hook Setup
Create .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.15
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
Install:
pip install pre-commit
pre-commit install
Now, Ruff runs automatically before every git commit.
π§© 8. GitHub Actions CI Integration
Letβs integrate Ruff into a lightweight GitHub Actions pipeline.
.github/workflows/lint.yml
name: Ruff Linting CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Ruff
run: pip install ruff
# πΉ Recommended: lint the code (no fixes)
- name: Run Ruff Linter
run: ruff check . --output-format=github
# πΉ Optional: Check formatting
- name: Check Ruff Formatting
run: ruff format --check .
π‘ Why --output-format=github?
This format makes lint results appear inline as annotations on your PR.
β‘ 9. Run Everything Locally
Try these locally:
ruff check . # Lint check
ruff check . --fix # Auto-fix issues
ruff format . # Format code
pytest # Run tests
π 10. Benchmark (Optional)
Hereβs an example of how fast Ruff runs compared to traditional linters.
Benchmark
π§© 11. Summary β End-to-End Flow
| Stage | Command | Purpose |
|---|---|---|
| Local development | ruff check . --fix |
Lint + auto-fix |
ruff format . |
Format code | |
pytest |
Run tests | |
| Pre-commit | pre-commit run --all-files |
Run Ruff before commits |
| CI pipeline |
ruff check . & ruff format --check .
|
Verify code cleanliness |
| Customization | Edit [tool.ruff] in pyproject.toml
|
Tailor lint rules |
β 12. Takeaways
- Ruff = One tool replacing many (Flake8, isort, pyupgrade, partial Black)
- Setup takes <5 minutes and improves local + CI performance drastically
-
Recommended pipeline commands:
ruff check .ruff format --check .
Configuration is easy via
pyproject.tomlUse
pre-commitfor best developer experience

Top comments (0)