Ruff vs Pylint vs Flake8: Python Linters Compared
Ruff, Pylint and Flake8 all check Python code for bugs and style. Compare speed, rules, plugins and config, and decide which one to use.
For most projects today, use Ruff as your linter, and add Pylint only if you want its deeper checks. Flake8 is the long-standing default that Ruff was built to replace. All three read your code without running it and report problems; they differ in speed, in how many rules they have, and in how you extend them.
At a glance
| Ruff | Pylint | Flake8 | |
|---|---|---|---|
| What it is | Linter and formatter in one tool | Static code analyser | Wrapper around PyFlakes, pycodestyle and McCabe |
| Rules | 900+ built in (973 in Ruff 0.17.3) | Roughly 400 (about 409 per Ruff’s FAQ) | Those three tools, plus plugins |
| Auto-fix | Yes | No (it reports and suggests) | No |
| Plugins | Rules are native; no third-party rules | Yes (“checkers”) | Yes, a large ecosystem |
| Config file | pyproject.toml or ruff.toml | pyproject.toml and others | setup.cfg, tox.ini or .flake8 |
| Speed | Claims 10-100x faster than Flake8 | Does more analysis, so slower in practice | Slower than Ruff |
The rule counts and Ruff’s compatibility claims come from Ruff’s own FAQ, so they are the Ruff project’s view. The speed figure is from Ruff’s README. Your own timing on your codebase is the number that matters.
Flake8: the long-standing default
Flake8 is a wrapper around three tools: PyFlakes for logical errors, pycodestyle for style, and McCabe for complexity. One command gives you one merged report.
flake8 path/to/code/
It adds # noqa comments to silence a line, and its plugin system produced a huge ecosystem (bugbear, docstring checks, and many more). That ecosystem is its strength and its cost: every plugin is another package to install and keep compatible.
It is configured in setup.cfg, tox.ini or .flake8, not pyproject.toml. Choose it today only if you rely on a plugin that Ruff doesn’t implement.
Pylint: the thorough one
Pylint describes itself as a static code analyser that checks for errors, enforces a coding standard, looks for code smells and suggests refactorings. It goes deeper than the others: Ruff’s FAQ notes that Pylint does more type inference, for instance it can check the number of arguments in a function call.
pylint mypackage
The price is speed and noise. It does more work per file, so expect it to run slower than the other two, and its defaults are opinionated, so most teams spend time tuning which messages to enable. Choose it if you want the extra analysis and are happy to configure it.
Ruff: fast, and replaces several tools
Ruff is written in Rust and aims to replace Flake8 (plus dozens of plugins), Black, isort and more with a single tool. Its README claims it is 10-100x faster than existing linters like Flake8, with over 900 built-in rules, including native versions of popular Flake8 plugins such as flake8-bugbear.
ruff check --fix .
Rules are switched on by prefix in pyproject.toml:
[tool.ruff.lint]
select = ["E", "F", "B", "I"]
Here E and F are the pycodestyle and PyFlakes rules, B is bugbear and I is import sorting. Note that select replaces Ruff’s default rule set (about 400 rules in the 0.17 series); to add rules on top of the defaults, use extend-select instead, as in what is Ruff. Unlike Flake8 and Pylint, Ruff can fix many violations automatically.
Its limits are the other side of the design: all rules are built in, so it doesn’t support custom or third-party rules, and it is not a pure replacement for Pylint, because each has rules the other lacks. For the formatting side, see Ruff vs Black vs autopep8. The Ruff resource page has the links.
How to choose
- New project: Ruff. One fast tool, configured in
pyproject.toml. - Existing Flake8 setup with a few plugins: try Ruff. Its documentation says it replaces Flake8 under those conditions. Check that each plugin you rely on is covered.
- You want deeper analysis: keep Pylint as well, as a slower second pass, and pair either linter with a type checker.
- Pinned to a Flake8-only plugin: stay on Flake8 until Ruff covers it.
Whichever you choose, run it in CI as well as locally, so the rules apply to everyone’s changes.
Frequently Asked Questions
Should I use Ruff, Pylint or Flake8?
For most new projects, Ruff: it is much faster, it covers the Flake8 rules plus many popular plugins, and it can auto-fix violations. Keep Pylint if you want its deeper analysis, such as type inference. Stay on Flake8 only if you depend on a plugin that Ruff doesn’t implement.
Is Ruff a drop-in replacement for Flake8?
Under the right conditions, yes. Ruff’s documentation says it can replace Flake8 when you use few or no plugins, run it alongside Black, and have Python 3 code, and that under those conditions it implements every Flake8 rule. It also reimplements many popular Flake8 plugins natively.
Is Ruff a replacement for Pylint?
Not entirely. Ruff’s FAQ says Pylint implements about 409 rules to Ruff’s 900 or more, with at least 209 overlapping, and that each has rules the other lacks. Pylint does more type inference than Ruff. Many people have switched successfully, especially when they also use a type checker.
Can I run Ruff and Pylint together?
Yes. A common setup is Ruff for fast checks on every save or commit and Pylint, or a type checker, as a slower second pass for the analysis Ruff doesn’t do.
Does Flake8 read pyproject.toml?
Not natively. Flake8’s documentation lists setup.cfg, tox.ini and .flake8 as its configuration locations. Ruff and Pylint can both be configured in pyproject.toml.