Should You Replace Black with Ruff?

Ruff has overtaken Black in monthly downloads and runs 30x faster. Here is when to switch and when to stay.

Updated 13 min read
Ruff vs Black Python formatter comparison

Ruff has overtaken Black in monthly PyPI downloads (≈180M vs ≈134.9M as of April 2026) and runs 30x faster as a formatter. One governance caveat every SERP comparison misses: OpenAI acquired Astral, Ruff's creator, in March 2026.

For new Python projects, Ruff is the clear choice: it replaces Black plus Flake8, isort, pyupgrade, and autoflake in one binary with >99.9% formatting compatibility. Black is the better call when PSF community governance is a hard requirement or when migrating a stable legacy codebase is more trouble than it's worth.

Key Takeaways

  • Ruff is best for new projects, CI-speed-sensitive pipelines, and teams replacing 5+ tools with one
  • Black is best for teams with PSF governance requirements or legacy codebases where migration cost outweighs speed gain
  • Ruff produces >99.9% identical output to Black with 4 documented intentional deviations
  • Both tools are free and MIT-licensed; Ruff is now under OpenAI's Codex division, Black under the Python Software Foundation
  • Ruff's monthly downloads (≈180M) now exceed Black's (≈134.9M) for the first time

Ruff vs Black: At a Glance

Feature

Ruff

Black

Best For

New projects, multi-tool replacement

Legacy codebases, PSF governance

Language

Rust

Python

Speed (formatting)

30x faster than Black

Baseline

Scope

Formatter + linter + import sorter + upgrader

Formatter only

Black Compatibility

>99.9% (4 intentional deviations)

N/A

License

MIT (OpenAI-owned via Astral acquisition)

MIT (Python Software Foundation)

Latest Release

v0.15.19 (June 24, 2026)

v26.5.1 (May 18, 2026)

Monthly PyPI Downloads

≈180M (April 2026)

≈134.9M

GitHub Stars

48,143

41,578

Primary Config Section

[tool.ruff] + [tool.ruff.format]

[tool.black]

What Is Ruff?

Ruff documentation homepage

Ruff is a Python linter and formatter written in Rust, created by Charlie Marsh at Astral in August 2022. The formatter launched in beta in October 2023 and became stable with v0.3.0 in 2024. In March 2026, OpenAI acquired Astral, absorbing Ruff, uv, and ty into OpenAI's Codex division; the MIT license is retained.

Ruff's value proposition is scope. ruff format handles Black-compatible formatting. ruff check covers linting with 900+ rules (Flake8's full rule set plus bugbear and dozens of plugin extensions). Import sorting replaces isort; code upgrades replace pyupgrade and autoflake. One binary, one config file, one CI step.

Strengths

  • 30x faster than Black on every published benchmark: Ruff formats the Zulip codebase in 0.10 seconds vs Black's 3.20 seconds; on a large codebase, Black's 443-second formatting job completes in under 1 second with Ruff
  • One tool replaces five: Black, Flake8, isort, pyupgrade, and autoflake, eliminating configuration drift and version-conflict debugging across multiple tools
  • >99.9% Black-compatible formatting output on real-world codebases, with only 4 documented intentional deviations from Black's style

Weaknesses

  • Corporate ownership changed in 2026: OpenAI acquired Astral in March 2026; Ruff's roadmap now sits inside OpenAI's Codex division, a vendor concentration risk some teams can't accept
  • "Drop-in" is 99.9%, not 100%: In Carberra's benchmark, running ruff format after Black on the TensorFlow codebase still reformatted 588 files, confirming stylistic differences at scale
  • Linter-formatter conflict on COM812: The trailing-comma rule conflicts with the formatter's own output, requiring ruff check --fix before ruff format or an explicit ignore = ["COM812"] in your config

What Is Black?

Black Python formatter on GitHub

Black is an opinionated Python code formatter created by Łukasz Langa in 2018 and transferred to the Python Software Foundation in 2021. Black's positioning is "the uncompromising Python code formatter": you accept its decisions, and in return you stop arguing about style. It has been the community standard for Python formatting since roughly 2019.

Black uses CalVer versioning (v26.5.1 released May 18, 2026). Development posture is maintenance mode: the PSF ensures continued, stable development, but Black is not racing to add features. It's formatter-only by design.

Strengths

  • PSF community governance: Black is controlled by the Python Software Foundation, a nonprofit with no corporate owner. For teams with policies against VC-backed or AI-company-owned tooling, Black is the structurally safe pick
  • Zero-configuration philosophy: Black makes all formatting decisions for you; the only meaningful knob is line length, so teams stop debating style and start shipping code
  • Massive ecosystem compatibility: Millions of existing Python repositories are Black-formatted; compatibility with Black's style is treated as a community standard

Weaknesses

  • Formatter only: A standard Black setup still requires Flake8 (linting), isort (import sorting), pyupgrade (syntax modernization), and autoflake (unused import removal): four additional tools, four config sections, four CI steps
  • Significantly slower: Black formats large codebases in seconds to minutes; Ruff formats the same jobs in under a second, a gap that matters in large monorepos
  • Declining community momentum: Modern Python project templates on r/Python (2025–2026) use uv + ruff + pyright with no mention of Black; GitHub stars (41,578) and monthly downloads (134.9M) now trail Ruff on both metrics

Speed: Ruff vs Black

Speed is Ruff's clearest advantage. Ruff is written in Rust; Black is written in Python.

On Astral's official Zulip benchmark: Ruff formats in 0.10 seconds, Black in 3.20 seconds, a 30x speedup. On large codebases, formatting jobs that take minutes in Black complete in under a second with Ruff.

The speedup extends to linting: Ruff lints CPython in ~0.3 seconds vs Flake8's ~12 seconds (40x faster).

Tim Abbott, Zulip lead developer: "This is just ridiculously fast... ruff is amazing."

One more data point worth knowing: with caching disabled, Ruff still outperforms Black with caching enabled. In real monorepo migrations, pre-commit stages drop from tens of seconds to well under a second.

Winner: Ruff. The performance gap holds across all published benchmarks and real-world migrations.

Formatting Output: How Different Is Ruff from Black?

For teams migrating from Black, the practical question is whether Ruff will introduce formatting churn on an existing codebase.

Ruff's formatter was explicitly designed as a Black drop-in. Astral documents four intentional deviations:

Deviation

Black behavior

Ruff behavior

Trailing EOL comments

May re-flow lines with trailing comments

Expands any statement containing trailing EOL comments

Pragma comments (# type, # noqa)

Avoids splitting # type lines; no special pragma handling

Ignores pragma comments when computing line width; avoids moving them

Unicode line-width

Unicode width for strings; character width for other tokens

Unicode width consistently for all tokens

Long nested-expression parenthesizing

PSF algorithm (Black 24+)

Prettier-style algorithm

On Django's codebase, only 34 of 2,772 files differ between Black and Ruff output. On a first ruff format run of a Black-formatted repo, expect ~0.1% of files to change. The changes are cosmetic; no semantic differences.

The pragma comment deviation is the one to watch on codebases that rely heavily on inline # noqa suppressions. Black can unintentionally broaden # noqa scope by collapsing lines; Ruff's handling is safer.

Winner: Tie for most codebases. Ruff's >99.9% compatibility holds at real-world scale. For teams with strict byte-identical requirements, Black wins by definition.

Scope: Formatter vs All-in-One Toolchain

Practitioners who frame this as a formatter-to-formatter swap are missing the bigger picture. Switching to Ruff means eliminating four other tools alongside Black, not just upgrading a formatter.

Black is a formatter only. A standard Python project using Black also needs:

  • Flake8 for linting (PEP 8 violations, undefined names, unused imports)
  • isort for import ordering
  • pyupgrade for syntax modernization (f-strings, walrus operators, newer typing syntax)
  • autoflake for removing unused imports
  • pydocstyle if you enforce docstring standards

Ruff covers all of these in one binary. Formatting maps to ruff format; linting to ruff check with 900+ rules (Flake8's full set plus bugbear extensions). Import sorting uses the I rule group, code upgrading the UP group, docstring checks the D group, and unused-import removal F401 auto-fix.

Sebastián Ramírez (@tiangolo), FastAPI's creator, described the moment FastAPI switched from Black to Ruff in October 2023:

So, @FastAPI now uses the Ruff formatter. 😎✨ Ruff alone is now replacing (for me): * flake8 * autoflake * isort * pyupgrade * black ...and Ruff is still crazy fast. 🚀 I keep intentionally adding broken code just to ensure it is indeed running. 🤪
Sebastián Ramírez · @tiangoloView on X

Charlie Marsh announced Pytest's migration three months later:

Pytest moves to Ruff! 🚀🚀🚀 Replaces autoflake, black, isort, pyupgrade, flake8, and pydocstyle... https://t.co/7JLfsOrWmR
Charlie Marsh · @charliermarshView on X

Corey Schafer (95k-view Ruff tutorial): "I've actually switched over to using it as my main linter and formatter for Python, which has allowed me to replace a few other tools with just this one."

On r/Python, the pattern is now the default in new projects. As u/JaffaB0y in r/Python (May 2025) asked: "why use black when you're using ruff for lint and it's got format builtin?"

Winner: Ruff. When scope matters, Ruff wins. For teams who want a formatter and nothing else, Black is cleanly scoped.

Configuration and Migration

Here is the pyproject.toml translation from Black to Ruff, based on Ruff's official migration guide:

Current Black config:

Text
[tool.black]
line-length = 88
target-version = ["py39"]           # list
skip-string-normalization = true
extend-exclude = '''                # regex
/(migrations|vendor)/
'''

Ruff equivalent:

Text
[tool.ruff]
line-length = 88
target-version = "py39"             # string, not a list

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]

[tool.ruff.format]
quote-style = "preserve"            # = skip-string-normalization
magic-trailing-comma = "respect"    # "ignore" = skip-magic-trailing-comma

Key-by-key translation table:

Black key

Ruff equivalent

Gotcha

line-length

line-length (under [tool.ruff])

Identical

target-version = ["py39"]

target-version = "py39"

String in Ruff, not a list

skip-string-normalization = true

[tool.ruff.format] quote-style = "preserve"

Section changes

skip-magic-trailing-comma = true

[tool.ruff.format] magic-trailing-comma = "ignore"

Section changes

extend-exclude (regex)

exclude (glob list, e.g., ["migrations", "vendor"])

Syntax changes

Full migration steps:

  1. Commit all pending changes (clean working tree)
  2. Install Ruff: pip install ruff or uv add --dev ruff
  3. Translate [tool.black] using the table above
  4. Remove old tools: pip uninstall black flake8 isort pyupgrade autoflake
  5. Run ruff check --fix . then ruff format .; this order matters (lint fixes first, then format)
  6. Update pre-commit hooks:
YAML
- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.15.19
  hooks:
    - id: ruff-check
      args: [--fix]
    - id: ruff-format
  1. Update CI/CD. Replace psf/black@stable and PyCQA/flake8 actions with:
YAML
- uses: astral-sh/ruff-action@v4
  with:
    args: "check --fix"
- uses: astral-sh/ruff-action@v4
  with:
    args: "format --check"
  1. Update VS Code: install the Ruff extension, set it as default formatter, enable Format on Save

Run order matters: ruff check --fix before ruff format. Running in reverse causes the formatter to write code the linter then flags, most visibly on the COM812 trailing-comma rule. Either fix the run order in pre-commit or add ignore = ["COM812"] to [tool.ruff.lint].

Winner: Tie. Black's single-tool config has less surface area to manage. Ruff's migration is a one-time cost with a five-tool reduction as the payoff.

Governance and Ownership in 2026

The governance contrast between Ruff and Black in 2026 is the sharpest in Python tooling history, and it's absent from every comparison article currently ranking on Google.

Ruff: Created at Astral with VC backing. In March 2026, OpenAI acquired Astral, absorbing Ruff, uv, and ty into the OpenAI Codex division with Charlie Marsh. The MIT license is retained, and OpenAI has publicly committed to open-source tooling, though the organizational concentration is real.

Black: Created by Łukasz Langa (CPython core developer, Python 3.8/3.9 Release Manager) in 2018 and transferred to the Python Software Foundation in 2021. No corporate owner, no VC: governed by the nonprofit steward of the Python language.

The community response to the OpenAI acquisition was measured but concerned. u/latkde in r/Python (April 2026): "Astral's business model always seemed unclear, and an acquihire is a relatively unsurprising outcome. We've all built on Astral tooling knowing that it was unsustainable. But having the fate of these tools chained to what may be the biggest bubble in tech economy history doesn't exactly soothe my worries."

The community's answer to concentration risk is the MIT license. u/menge101 in r/Python (April 2026): "Keep in mind, ruff and ty are MIT licensed. UV is apache2 and MIT licensed. We can fork these things if needed to stop from being trapped into anything by OpenAI."

There's also a legitimate ethics objection that predates the acquisition. Anthony Sottile, maintainer of pyupgrade and other tools Ruff reimplemented, named it in his YouTube critique:

"Ruff kind of kills a lot of projects that I was working on, and I don't really feel incentivized to contribute to this space anymore, especially when someone is profiting off my work and the work of others in the community."

The OpenAI acquisition makes that observation more pointed, not less.

Winner: Black. If PSF governance or corporate-ownership concerns apply to your team's policy, Black is the structurally safe pick and is likely to stay that way.

Community Adoption

By raw numbers, Ruff has crossed a threshold Black held for years.

Metric

Ruff

Black

Monthly PyPI downloads

≈180M (April 2026)

≈134.9M

GitHub stars

48,143

41,578

GitHub releases

415

55

Release cadence vs Black

~7.5x faster

Baseline

Major adopters

FastAPI, Pandas, Hugging Face, Apache Airflow, SciPy, Pydantic

Deep lock-in across millions of legacy repos

Nick Schrock, co-creator of GraphQL: "Why is Ruff a gamechanger? Primarily because it is nearly 1000x faster. Literally, not a typo."

Timothy Crosley, creator of isort (which Ruff replaces): "Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe it was working till I intentionally introduced some errors."

u/Khavel_dev in r/Python (May 2026): "uv and ruff are the obvious ones but they genuinely changed the daily experience for me. Before uv I'd wait 30+ seconds to create an env and install deps. Now it's basically instant for most projects."

Google Trends shows ruff python outpacing black formatter by 1.5x–3x consistently, with Ruff peaking at index 100 in March 2026, coinciding with the Astral acquisition announcement and a surge in community discussion. Modern Python project templates on r/Python (2025–2026) list uv + ruff + basedpyright with Black absent.

Winner: Ruff. Black maintains a larger installed base in legacy codebases, but new projects are defaulting to Ruff.

"Pricing": Toolchain Cost Comparison

Both Ruff and Black are free and MIT-licensed. The real cost difference is toolchain overhead.

Black stack:

  • pip install black flake8 isort pyupgrade autoflake (five separate packages to install, pin, and update)
  • Five [tool.X] config sections to maintain in pyproject.toml
  • Five pre-commit hooks (black, flake8, isort, pyupgrade, autoflake)
  • Five tool versions to track across the team

Ruff stack:

  • pip install ruff (one package)
  • One [tool.ruff] config section (plus [tool.ruff.format] and [tool.ruff.lint] subsections)
  • Two pre-commit hooks (ruff-check, ruff-format)
  • One version to pin

No licensing cost for either tool. The real cost comparison is maintenance overhead and CI time, both of which favor Ruff on anything beyond a small solo project.

The Verdict: Ruff or Black?

Choose Ruff if you're starting a new Python project, care about CI speed, want to consolidate five tools into one, or are comfortable with OpenAI's stewardship of an MIT-licensed codebase. For the vast majority of Python teams in 2026, this is the right call.

Choose Black if PSF community governance is a hard requirement or your organization has a policy against AI-company-owned tooling. It's also the right call on a stable legacy codebase where a ~0.1% formatting diff and migration effort aren't worth the speed payoff.

The community default has shifted. Ruff has overtaken Black in downloads, dominates new-project templates, and offers a meaningfully larger scope for the same zero-dollar price. If you're starting a new repo or auditing your toolchain, Ruff is the move; if you're already on Black and everything works, staying put is reasonable, with the PSF ensuring stable maintenance.

Frequently Asked Questions

Related Articles