SpikeMe
← Comparisons
Python

Ruff vs Flake8

updated on July 13, 2026

Ruff vs Flake8

Ruff and Flake8 compared on speed (Rust vs Python), scope (lint + format + imports in one binary vs linter + plugins) and auto-fix, with real PyPI data.

FactRuffFlake8
Current version0.15.217.3.0
Downloads/week (npm)336,795,60672,243,867
LicenseMITMIT
CriterionRuffFlake8
Speedwritten in Rust, orders of magnitude fasterpure Python, slower on large codebases
Scopelinter + formatter + import sorting in one binarylinter only; formatter and imports live in separate tools
Auto-fixfixes automatically with --fixreports only, no fixes
Rule coveragereimplements Flake8, isort, pyupgrade, pydocstyle and morepyflakes + pycodestyle + mccabe, extended by plugins
Configurationnative in pyproject.toml under [tool.ruff]setup.cfg/.flake8/tox.ini, each plugin its own
Extensibilitybuilt-in rules; no third-party pluginslarge plugin ecosystem (flake8-bugbear, etc.)
Maturity and stabilitypre-1.0 (0.x), rule set still evolvesstable API, years of production-tested plugins

Context

Ruff and Flake8 solve the same problem (surfacing lint errors and style deviations in Python code), but from opposite foundations. Flake8 is the established checker of the ecosystem: a pure-Python orchestrator that bundles three classic tools, pyflakes (logic errors), pycodestyle (PEP 8 style) and mccabe (complexity), and extends through a large ecosystem of plugins like flake8-bugbear. Ruff, built by Astral, is a single binary written in Rust that reimplements the rules of Flake8, isort, pyupgrade, pydocstyle and dozens of other tools, runs orders of magnitude faster, fixes much of what it finds on its own with --fix, and even ships a built-in formatter that is Black-compatible.

The decisive variable is not which one finds more issues: it is whether you want a single, fast tool with auto-fix replacing the whole stack, or whether you depend on specific plugins and a stable API that years of ecosystem have validated. Ruff is pre-1.0 (0.x versions): the rule set and some defaults still shift between releases, which is the price of how fast it moves.

When to choose Ruff

Ruff makes the most sense when lint slowness is a pain, or when the quality-tooling stack has become a zoo of configs. A project that today runs flake8 + isort + pyupgrade (and maybe black to format) can collapse all of it into one binary: ruff check lints with the equivalent rules, ruff check --fix automatically fixes what it safely can, ruff format formats in the Black style, and isort's import sorting becomes a rule (I) inside the same pass. On large codebases the speed difference is dramatic: what took tens of seconds now runs in fractions of a second, which changes the ergonomics in the editor and in pre-commit.

# pyproject.toml
[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
# equivalents to pyflakes (F), pycodestyle (E), isort (I), bugbear (B), pyupgrade (UP)
select = ["E", "F", "I", "B", "UP"]
ruff check --fix .   # report and fix what is safe
ruff format .        # format in the Black style

At around 337 million downloads per week on PyPI, Ruff has become the default in new projects, driven precisely by that unification. The cost is maturity: being on 0.x, its rule catalog and some behaviors still evolve, and it does not accept third-party plugins, so a very specific rule that only exists as a Flake8 plugin may not have an equivalent yet. Pin the version in your lockfile so you are not surprised by changes between releases.

When to choose Flake8

Flake8 is still the right call when the project depends on a specific ecosystem plugin that Ruff has not reimplemented yet, or when stability matters more than speed. Years as the reference checker produced an ecosystem of production-tested plugins and a predictable API: configuration rarely changes behavior between versions, and each rule has a known, documented code. For a codebase that is already configured, mature, and whose lint is not a time bottleneck, migrating brings little immediate payoff.

# .flake8 (or setup.cfg)
[flake8]
max-line-length = 100
max-complexity = 10
extend-select = B  # enables the flake8-bugbear plugin
extend-ignore = E203
flake8 .   # reports the issues; fixing is manual

The difference shows up in the same flow: Flake8 reports but does not fix, and formatting or sorting imports is left to separate tools (black, isort), each with its own configuration. In exchange, you get a stable rule set and access to niche plugins that do not yet exist in Ruff. At around 72 million downloads per week, Flake8 remains widely installed, sustained by CIs and mature projects with no strong reason to swap a configuration that works.

Verdict

Reduced to its essence, the choice turns on a trade-off: speed and unification against stability and plugins. Ruff replaces the whole stack (linter, formatter, import sorter) with a single, fast binary that auto-fixes, and for the vast majority of projects, especially new ones, it is the decision that saves CI and configuration time from the start. The honest caveat is the 0.x stage: pin the version and expect rules and defaults to still move between releases.

Flake8 rarely disappoints when what you need is a stable API or a specific ecosystem plugin that Ruff does not cover yet. If the codebase is already configured, lint is not a bottleneck, and there is a real plugin dependency, there is no urgency to migrate. But for a project starting today, or for anyone suffering from slow lint and scattered configs, Ruff is the natural bet, and its growing adoption reflects that. Choose by the mix of speed and scope your project actually needs, not by habit.

Ruff

Choose Ruff if…

Choose Ruff to unify lint, format and import sorting into one fast tool with auto-fix, accepting that its rule set still evolves before 1.0.

Flake8

Choose Flake8 if…

Choose Flake8 when you depend on specific ecosystem plugins or want a stable, mature API, and speed is not a bottleneck in your codebase.

The numbers above came from the registry, with source and date. Still, this comparison is generic: the right answer depends on versions, your team and what already exists in your project.

Generate the spike for YOUR stack

Share

XLinkedIn