Ruff: Fast Python Linter and Formatter in Rust
What Ruff is
Ruff is a Python linter and code formatter written in Rust, built by Astral, the company that also makes the uv package manager and the ty type checker. The README's one-line description is "an extremely fast Python linter and code formatter", and speed is the headline: the project claims Ruff is 10 to 100 times faster than existing linters such as Flake8 and formatters such as Black, and illustrates it with a benchmark of linting the CPython codebase from scratch. Those numbers are the project's own; the practical point is that Ruff is fast enough to run on every save and in every pre-commit hook without anyone noticing.
The second pitch is consolidation. A typical Python project has accumulated a stack of separate tools: Flake8 with a handful of plugins, isort for import ordering, Black for formatting, pyupgrade for modernising syntax, autoflake for removing unused imports, pydocstyle for docstrings. Each has its own configuration, its own release cycle and its own way of being wired into CI. The README says Ruff can replace Flake8 (plus dozens of plugins), Black, isort, pydocstyle, pyupgrade, autoflake and more behind one command-line interface and one configuration file. It ships over 900 built-in rules, many of them native Rust re-implementations of popular Flake8 plugins such as flake8-bugbear.
Ruff is MIT-licensed and distributed on PyPI as ruff, with prebuilt wheels so installing it does not require a Rust toolchain. The README lists Apache Airflow, Apache Superset, FastAPI, Hugging Face Transformers, pandas and SciPy among the open-source projects that use it. It is aimed at anyone who writes Python: application teams who want one fast tool in CI, library maintainers who want consistent style across contributors, and monorepo owners who need different rules in different directories.
How it works
One binary, two main commands
Everything lives in a single ruff executable. ruff check is the linter's entry point: it takes files or directories, recursively discovers Python files and reports violations, optionally fixing the fixable ones. ruff format is the formatter's entry point and rewrites files in place, or with --check reports unformatted files and exits non-zero without writing anything. The same binary also contains ruff server, the language server that powers editor integrations. The two tools are independent: the FAQ is explicit that you can use Ruff only as a formatter or only as a linter.
Rules and selectors
The linter uses Flake8-style rule codes: an alphabetic prefix for the source tool followed by digits, such as F401 (an unused import, from Pyflakes) or E501 (a pycodestyle rule). The lint.select, lint.extend-select and lint.ignore settings accept full codes or prefixes, so select = ["E", "F"] turns on everything from pycodestyle and Pyflakes. There is also a special ALL selector; the docs advise using it with discretion because it silently enables new rules on every upgrade, and recommend starting small and adding one group at a time. When settings come from several places, Ruff takes the highest-priority select as the base and applies extend-select and ignore on top, with command-line flags beating the current pyproject.toml, which beats inherited ones.
In preview mode the linter also understands rule categories that group rules by the kind of problem: correctness, suspicious, complexity, performance and style form the default set, while security, formatting, pedantic and restriction are off by default. Preview also lets selectors and suppression comments use human-readable rule names like unused-import instead of codes.
Hierarchical configuration
Ruff reads pyproject.toml (under [tool.ruff]), ruff.toml or .ruff.toml. Like ESLint, it supports cascading configuration: for each file it uses the closest config file in the directory hierarchy, resolving paths such as exclude globs relative to that file's directory. A pyproject.toml without a [tool.ruff] section is skipped during that search, and a file passed with --config applies to every analysed file. This is what makes Ruff monorepo-friendly: a tests/ or scripts/ directory can carry its own looser rules. By default Ruff discovers *.py, *.pyi and *.ipynb files along with its own config files, and Jupyter notebooks are linted and formatted out of the box. A built-in cache avoids re-analysing unchanged files.
Where the code comes from
The acknowledgements explain the lineage. The linter draws on the APIs and implementation details of Flake8, Pyflakes, pycodestyle, pydocstyle, pyupgrade and isort, in some cases as direct Rust ports. The formatter is built on a fork of Rome's rome_formatter and borrows from Rome, Prettier and Black. The import resolver is based on Pyright's resolution algorithm.
Key features
- Over 900 lint rules. Native re-implementations of Pyflakes, a subset of pycodestyle, and plugins including flake8-bugbear, flake8-bandit, flake8-simplify, flake8-pytest-style, pep8-naming, pydocstyle, pyupgrade, isort, mccabe, tryceratops and many more.
- Automatic fixes with a safety model.
ruff check --fixapplies only fixes labelled safe, meaning they preserve runtime behaviour; unsafe fixes, which could change behaviour or remove comments, need--unsafe-fixesor theunsafe-fixessetting, and per-rule safety can be adjusted. - A Black-compatible formatter. The docs say that on large Black-formatted projects such as Django and Zulip more than 99.9% of lines come out identical, with a small documented list of deliberate deviations.
- A few formatter options Black lacks. Quote style, indent style (including tabs), line endings, and opt-in formatting of code examples inside docstrings in doctest, Markdown and reStructuredText forms.
- Import sorting. Implemented as lint rules (the
Igroup), compatible with isort's action comments such as# isort: skip_file. - Flexible suppression. Flake8-style
# noqa: F841comments, file-level suppressions,ruff: ignorecomments that can cover a whole multi-line statement, range suppressions, and--add-noqato bulk-annotate existing violations when adopting Ruff on legacy code. - Watch mode and exit-code control.
ruff check --watchre-lints on change;--exit-zeroand--exit-non-zero-on-fixtune CI behaviour. - Jupyter Notebook support. Notebooks are discovered by default, with options to only lint or only format them and per-notebook rule ignores.
- A built-in language server.
ruff serverprovides diagnostics, code actions and formatting over LSP; it replaced the olderruff-lspand was stabilised in v0.5.3. - Preview mode.
--previeworpreview = trueopts into unstable rules, fixes and formatter style changes, separately for linting and formatting if needed.
Getting started
The README recommends uv. To try Ruff without installing it, run it through uvx (the README pins the current release):
uvx [email protected] check # Lint all files in the current directory.
uvx [email protected] format # Format all files in the current directory.
To install it globally or as a project dev dependency, or with pip or pipx:
uv tool install ruff@latest # Install Ruff globally.
uv add --dev ruff # Or add Ruff to your project.
pip install ruff
pipx install ruff
Since version 0.5.0 there are also standalone installers, and the installation page lists Homebrew, conda-forge, pkgx, Arch, Alpine and openSUSE packages plus a Docker image:
curl -LsSf https://astral.sh/ruff/install.sh | sh
brew install ruff
conda install -c conda-forge ruff
docker run -v .:/io --rm ghcr.io/astral-sh/ruff check
Day-to-day usage is two commands:
ruff check # Lint all files in the current directory (and any subdirectories).
ruff format # Format all files in the current directory (and any subdirectories).
Rules can be selected on the command line, and any other setting can be passed through the catch-all --config flag:
ruff check --select F401 --select F403 --quiet
ruff check --config "lint.per-file-ignores = {'some_file.py' = ['F841']}"
Because the formatter does not sort imports, the formatter docs give this sequence for projects that want both:
ruff check --select I --fix
ruff format
For CI, the README shows a pre-commit configuration using the ruff-pre-commit repository with ruff-check (with --fix) and ruff-format hooks, and a GitHub Actions workflow using astral-sh/ruff-action. The integrations page also covers GitLab CI. In a pyproject.toml, remember that every section from the README's example configuration needs the tool.ruff prefix, so [lint] becomes [tool.ruff.lint].
Use cases
- Collapsing a lint stack. A project running Flake8 with bugbear, comprehensions and simplify plugins, plus isort and pyupgrade, can move to one
[tool.ruff.lint]section and one CI step. - Replacing Black. Teams can switch to
ruff formatwith near-identical output and gain options such as single quotes or tab indentation if they want them. - Fast pre-commit and editor feedback. At its speed, linting the whole repository on every commit or every save is practical, which is the experience several testimonials in the README describe.
- Adopting linting on a legacy codebase. Enable a rule set, run
ruff check --add-noqato mark existing violations, and enforce the rules only on new code from that point. - Monorepos with mixed standards. Nested
ruff.tomlfiles let a strict library package and a looser scripts directory coexist in one repository. - Modernising syntax after a Python upgrade. The pyupgrade-derived
UPrules and their fixes rewrite code to newer idioms oncetarget-versionis raised. - Data science notebooks. Notebooks are linted and formatted alongside regular modules without extra plugins.
How it compares
Flake8. The FAQ says Ruff can be a drop-in replacement for Flake8 when Flake8 is used with no or few plugins, alongside Black, on Python 3 code: under those conditions Ruff implements every Flake8 rule, meaning all the Pyflakes F rules and a subset of pycodestyle's E and W rules. Some plugin rules use different codes in Ruff (for example TID252 for flake8-tidy-imports' I252), and Ruff omits some of bugbear's opinionated rules. The main limitation is that Ruff has no custom rules or third-party plugins; popular plugins are reimplemented inside Ruff instead.
Pylint. The FAQ puts Pylint at about 409 rules against Ruff's 900-plus, with at least 209 overlapping. Pylint does more type inference, such as checking the number of arguments in a call, so neither is a pure replacement for the other. Ruff can autofix its own violations; Pylint supports plugin checkers. Enabling Ruff's PL group may surface rules from Pylint extensions that your Pylint config never enabled.
Black. The formatter targets Black's stable style and near-identical output, but the docs warn it is not meant to be used interchangeably with Black on an ongoing basis because of its deliberate deviations. Pick one.
Type checkers. Ruff is a linter, not a type checker. The FAQ recommends pairing it with ty, Mypy, Pyright or Pyre: Ruff flags things like unused imports that type checkers ignore, while a type checker catches an integer passed where a string is expected, which Ruff would miss. The editor docs likewise suggest the ty language server for navigation and completion alongside Ruff.
Things to know before adopting
- No stable API yet. Ruff is still pre-1.0 and uses its minor version for breaking changes and its patch version for fixes. Promoting a rule to stable, changing a stable rule's behaviour, changing the default rule set or changing the formatter's stable style all bump the minor version, so pin the version in CI and pre-commit and read release notes before upgrading.
ALLmoves under you. SelectingALLenables every new rule that ships; the docs recommend explicitlint.selectlists instead.- Unsafe fixes can change behaviour. Safe fixes are the default, but even then the FAQ notes that Python's dynamic nature makes complete certainty hard and asks users to report safe fixes that break code. Review diffs from
--fix, and treat--unsafe-fixesas something to run deliberately. - No plugin system. If you rely on an in-house Flake8 plugin or a niche third-party one that Ruff has not reimplemented, you will lose that check or need to keep Flake8 for it; a plugin system is described as in scope but not yet available.
- Formatter and linter can conflict. The formatter docs list lint rules to avoid when using both, including indentation rules such as
W191andE111, the flake8-quotesQrules andCOM812; none are in the default configuration.E501can still fire on formatted code, because line wrapping is best-effort. - Import sorting is a lint step.
ruff formatalone will not sort imports; runruff check --select I --fixfirst. - Python version support. Ruff can lint code for Python 3.7 onwards, including 3.15, and does not support Python 2. Set
target-version(orrequires-python) so version-dependent rules behave correctly. - Preview is opt-in and unstable. Preview rules and style changes may change before stabilisation, and warnings about deprecated features may become errors in preview mode.
- Company-backed. Ruff is developed by Astral, a company; the code is MIT-licensed, so that matters mainly for roadmap and stewardship, not licensing.
Project activity
As of November 2026 the astral-sh/ruff repository has about 50,500 stars and around 2,600 forks on GitHub. It was created in August 2022, is written in Rust and is licensed under MIT. The latest release at the time of writing is 0.17.4, published on 5 November 2026, and the main branch receives commits daily. Ruff's crates are also published to crates.io, though their Rust interfaces do not follow semantic versioning. The rule reference, settings reference and an online playground are linked from the documentation.
The source is at github.com/astral-sh/ruff, and the documentation is at docs.astral.sh/ruff.
Enjoying this project?
Discover more amazing open-source projects on TechLogHub. We curate the best developer tools and projects.
Repository:https://github.com/astral-sh/ruff
GitHub - astral-sh/ruff: Ruff: Fast Python Linter and Formatter in Rust
Ruff is an MIT-licensed Python linter and code formatter written in Rust by Astral. It bundles 900+ lint rules, autofixes, isort-style import sorting and a Blac...
github - astral-sh/ruff
Related Projects
Maintain Ruff: Fast Python Linter and Formatter in Rust? Add the badge to your README
Show that the project is featured on TechLogHub and send readers to this write-up.
[](https://techloghub.com/open-source/ruff-python-linter?utm_source=techloghub_badge&utm_medium=referral&utm_campaign=readme)

