Ruff: Supercharge Your Python Linting and Formatting
Learn Ruff, the ultra-fast Python linter and formatter.
20+ years shipping production Python across data and backend systems. Written from production experience, not tutorials.
- ✓Basic knowledge of Python syntax and common linters (Flake8, Black).
- ✓Python 3.7+ installed on your system.
- ✓Familiarity with command-line tools and configuration files.
- Ruff is a Rust-based linter and formatter that is 10-100x faster than Flake8 and Black.
- It replaces multiple tools (Flake8, isort, Black, pyflakes) with a single binary.
- Configuration is done via pyproject.toml or ruff.toml.
- It supports over 700 lint rules and automatic fix.
- Ideal for CI/CD pipelines and pre-commit hooks.
Think of Ruff as a super-fast code inspector and auto-cleaner. While other tools take minutes to check your code, Ruff does it in seconds, like a race car compared to a bicycle. It catches mistakes, enforces style, and even fixes many issues automatically.
As your Python projects grow, maintaining code quality becomes critical. Linters and formatters help enforce consistent style and catch bugs early. But traditional tools like Flake8, Black, and isort can be slow, especially on large codebases. Enter Ruff: a blazing-fast linter and formatter written in Rust. Ruff is designed to be a drop-in replacement for many existing tools, offering 10-100x speed improvements.
Ruff supports over 700 lint rules, including those from Flake8, pyflakes, pycodestyle, and isort. It also provides automatic fixes for many issues. Its speed makes it ideal for pre-commit hooks and CI pipelines, where every second counts. In this tutorial, you'll learn how to install Ruff, configure it for your project, integrate it into your workflow, and debug common issues in production. By the end, you'll be able to supercharge your Python development with minimal effort.
Installing Ruff
Ruff is distributed as a single binary, making installation simple. You can install it via pip, Homebrew, or download the binary from GitHub. The recommended way is using pip:
``bash pip install ruff ``
For macOS users, Homebrew is also an option:
``bash brew install ruff ``
After installation, verify it works:
``bash ruff --version ``
Ruff also supports installation as a pre-commit hook. Add this to your .pre-commit-config.yaml:
``yaml - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.0 hooks: - id: ruff args: [--fix] - id: ruff-format ``
This ensures Ruff runs automatically before each commit, catching issues early.
Configuring Ruff
Ruff is configured via pyproject.toml or a dedicated ruff.toml file. The configuration allows you to select rules, ignore certain files, and set formatting options. Here's a basic example:
```toml [tool.ruff] # Enable pycodestyle (E), pyflakes (F), and isort (I) rules. select = ["E", "F", "I"]
# Ignore line length violations in tests. ignore = ["E501"]
# Exclude generated files. exclude = [".pyc", "__pycache__", "migrations/"]
# Line length. line-length = 88
[tool.ruff.format] # Use single quotes instead of double quotes. quote-style = "single" ```
You can also configure per-file ignores:
``toml [tool.ruff.per-file-ignores] "__init__.py" = ["F401"] ``
Ruff supports many rule categories: E (pycodestyle), F (pyflakes), I (isort), N (naming), and more. Use ruff linter to list all rules.
To check your configuration, run:
``bash ruff check --show-settings ``
Running Ruff as a Linter
Ruff's linter checks your code for errors, style violations, and anti-patterns. To run the linter, use:
``bash ruff check . ``
This will scan all Python files in the current directory. You can also specify individual files:
``bash ruff check myfile.py ``
Ruff can automatically fix many issues with the --fix flag:
``bash ruff check --fix . ``
For unsafe fixes (e.g., removing unused imports that might have side effects), use --unsafe-fixes:
``bash ruff check --fix --unsafe-fixes . ``
To see which rules are being applied, use --show-fixes:
``bash ruff check --fix --show-fixes . ``
You can also output results in different formats, like JSON for CI integration:
``bash ruff check --output-format json . ``
ruff check --output-format github to annotate pull requests with lint errors.ruff check to lint and --fix to auto-correct issues. Unsafe fixes require manual review.Formatting Code with Ruff
Ruff also includes a formatter, which is an alternative to Black. It aims to be compatible with Black's style but faster. To format your code, run:
``bash ruff format . ``
You can preview changes without applying them using --diff:
``bash ruff format --diff . ``
Ruff's formatter respects the line-length setting from your configuration. It also supports options like quote-style (single or double quotes) and indent-style (spaces or tabs).
Example formatting:
```python # Before formatting def my_function( arg1,arg2 ): return arg1+arg2
# After ruff format def my_function(arg1, arg2): return arg1 + arg2 ```
Ruff's formatter is designed to be deterministic and consistent, reducing debates about code style.
ruff format --check in CI to ensure code is formatted without modifying files.Integrating Ruff with Pre-commit
Pre-commit hooks automate code quality checks before each commit. Ruff provides official pre-commit hooks for both linting and formatting. Add the following to your .pre-commit-config.yaml:
``yaml repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.0 hooks: - id: ruff args: [--fix] - id: ruff-format ``
Then run pre-commit install to activate the hooks. Now, every time you commit, Ruff will lint and format your staged files. If issues are found, the commit will be blocked until fixed.
You can also run the hooks manually on all files:
``bash pre-commit run --all-files ``
This integration ensures consistent code quality across the team.
args: [--exit-non-zero-on-fix] to fail the commit if Ruff makes changes, requiring a re-commit.Advanced Configuration: Rule Selection and Ignoring
Ruff offers granular control over which rules to apply. You can select entire categories or individual rules. For example:
``toml [tool.ruff] select = ["E", "F", "I", "N", "W"] ignore = ["E501", "W191"] ``
You can also enable rules that are not part of any category using their full code (e.g., RUF100).
Per-file ignores are useful for exceptions:
``toml [tool.ruff.per-file-ignores] "tests/*" = ["S101"] # Allow assert in tests "__init__.py" = ["F401"] # Allow unused imports ``
Ruff also supports extend-select and extend-ignore to add rules from different sources.
For formatting, you can configure:
``toml [tool.ruff.format] quote-style = "double" indent-style = "space" line-ending = "lf" ``
These settings help tailor Ruff to your project's needs.
ruff check --statistics to see which rules are triggered most often and adjust configuration accordingly.Performance Benchmarks and CI Integration
Ruff's main selling point is speed. In benchmarks, Ruff is 10-100x faster than Flake8 and Black. For example, on a 10,000-file codebase, Flake8 might take 5 minutes, while Ruff finishes in under 10 seconds. This speed makes it ideal for CI pipelines where every second counts.
To integrate Ruff into CI (e.g., GitHub Actions), add a step:
``yaml - name: Lint with Ruff run: | pip install ruff ruff check --output-format github . ``
For formatting checks:
``yaml - name: Check formatting with Ruff run: | pip install ruff ruff format --check . ``
You can also cache Ruff to speed up installations:
``yaml - name: Cache Ruff uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-ruff-${{ hashFiles('pyproject.toml') }} ``
This ensures fast, consistent checks.
The Slow CI Pipeline That Cost Hours
- Always profile your CI pipeline to identify bottlenecks.
- Consider replacing multiple tools with a single, faster alternative.
- Ruff's speed makes it ideal for large codebases.
- Use pre-commit hooks with Ruff to catch issues before CI.
- Monitor tool versions and updates for performance improvements.
--ignore or per-file ignores.--diff to preview changes.ruff check --select RUF100ruff rule RUF100| File | Command / Code | Purpose |
|---|---|---|
| pyproject.toml | [tool.ruff] | Configuring Ruff |
| example_lint.py | def foo(): | Running Ruff as a Linter |
| format_example.py | x = [1,2,3,4,5] | Formatting Code with Ruff |
| .pre-commit-config.yaml | repos: | Integrating Ruff with Pre-commit |
| advanced_config.toml | [tool.ruff] | Advanced Configuration |
| ci.yml | name: Lint | Performance Benchmarks and CI Integration |
Key takeaways
ruff check --fix for auto-fixes and ruff format for formatting.Interview Questions on This Topic
What is Ruff and how does it differ from traditional linters like Flake8?
Frequently Asked Questions
20+ years shipping production Python across data and backend systems. Written from production experience, not tutorials.
That's Advanced Python. Mark it forged?
3 min read · try the examples if you haven't