Ismat Samadov
  • Tags
  • About
18 min read/1 views

uv and ruff Replaced pip, flake8, and black — The New Python Toolchain in 2026

uv is 10-100x faster than pip and replaces 7 tools. ruff replaces 10 linting/formatting tools. Migration takes 5 minutes. Here's how.

PythonDeveloper ToolsOpen SourcePerformance

Related Articles

Testing LLM Applications Is Nothing Like Testing Regular Software — Here's What Actually Works

14 min read

OpenTelemetry Is Eating Datadog's Lunch — The Open-Source Observability Stack in 2026

14 min read

Rate Limiting, Circuit Breakers, and Backpressure: The Three Patterns That Keep Distributed Systems Alive

18 min read

Enjoyed this article?

Get new posts delivered to your inbox. No spam, unsubscribe anytime.

On this page

  • The Numbers
  • What uv Actually Replaces
  • What Ruff Actually Replaces
  • The 2026 Style
  • The Migration That Takes 5 Minutes
  • From pip + requirements.txt to uv
  • From pip to uv (Drop-in Mode)
  • From Flake8 + Black + isort to Ruff
  • The pyproject.toml That Replaces Everything
  • Who's Already Using This Stack
  • The Elephant in the Room: OpenAI Bought Astral
  • What Other Articles Get Wrong
  • The Honest Drawbacks
  • The Complete Toolchain: 2026 Edition
  • ty: The Missing Piece
  • What I Actually Think
  • Sources

© 2026 Ismat Samadov

RSS

OpenAI's Codex platform — 2 million weekly active users — switched from pip to uv internally. The result: approximately 1 million minutes of compute time saved every week. Not per year. Per week. That single stat tells you everything about where Python tooling is headed in 2026.

Two years ago, most Python developers used pip for packages, flake8 for linting, black for formatting, and isort for import sorting. Four separate tools, four separate configurations, four separate maintenance burdens. Today, two Rust-based tools — uv and ruff — have replaced all of them. And the numbers aren't even close.


The Numbers

uv now pulls over 126 million monthly downloads on PyPI, surpassing Poetry's roughly 75 million. The astral-sh/uv repository has 82,600+ GitHub stars. In the 2025 Stack Overflow Developer Survey, uv was named the most admired technology with 74% admiration — across all categories, not just Python.

Ruff is even bigger by raw download numbers: 180 million monthly downloads on PyPI. It's been adopted by FastAPI, pandas, Apache Airflow, pydantic, and Hugging Face. The latest release is v0.15.7, and the tool now implements rules from dozens of linting plugins that previously required separate installations.

Both tools are built by Astral, a company founded by Charlie Marsh in 2023. In March 2026, OpenAI announced it would acquire Astral, bringing the team into OpenAI's Codex division. More on that later — it's complicated.


What uv Actually Replaces

uv isn't just a faster pip. It replaces the entire Python project management stack:

ToolWhat It Diduv Replacement
pipPackage installationuv pip install or uv add
pip-toolsDependency lockinguv lock
virtualenv / venvVirtual environmentsuv venv (80x faster)
pyenvPython version managementuv python install
PoetryProject management + lockinguv init + uv add + uv lock
pipxGlobal tool installationuv tool install
pip-compileRequirements compilationuv pip compile

That's seven tools replaced by one. And the performance gap is absurd:

Operationpip / traditionaluvSpeedup
Package installation (warm cache)45-60sunder 5s~10x
Virtual environment creation~4s (venv)~0.05s~80x
Dependency resolution30-35sunder 1s~30-100x
Adding a single package~6s (pip-tools)under 1s~6x
Lock file generation (cold)~35s (pip-tools)~8s~4x

The speed comes from Rust. uv's dependency resolver runs in parallel, downloads packages concurrently, and uses a global cache that deduplicates packages across projects. When you create a virtual environment with uv, it hard-links packages from the cache instead of copying them — so "installing" a cached package is essentially free.


What Ruff Actually Replaces

Ruff consolidates even more tools than uv:

ToolWhat It DidRuff Replacement
Flake8Lintingruff check
BlackCode formattingruff format
isortImport sortingruff check --select I
pyupgradePython version upgradesruff check --select UP
autoflakeRemove unused importsruff check --select F401
pydocstyleDocstring lintingruff check --select D
pyflakesError detectionBuilt-in
pycodestylePEP 8 checkingBuilt-in
BanditSecurity lintingruff check --select S
flake8-bugbearBug detectionruff check --select B

That's ten tools. One config file. One command.

The speed difference is 10-100x faster than any individual Python-based tool. Ruff can lint an entire large codebase in milliseconds where flake8 takes seconds. On the CPython standard library (~630,000 lines), ruff completes in under 200 milliseconds. Flake8 takes over 12 seconds on the same codebase.

And ruff doesn't just check — it fixes. Running ruff check --fix auto-corrects hundreds of issue types: unused imports, outdated syntax patterns, missing __all__ definitions, f-string conversions, and more.

The 2026 Style

Ruff v0.15.0, released in February 2026, introduced a new "2026" formatting style. The changes are small but meaningful — lambda parameters stay on one line with parenthesized bodies, and unparenthesized except blocks are enforced for Python 3.14+ (following PEP 758). This is what "living tooling" looks like: the formatter evolves with the language.


The Migration That Takes 5 Minutes

From pip + requirements.txt to uv

Here's the actual process. It's embarrassingly simple.

Step 1: Install uv

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Or with pip (if you appreciate the irony)
pip install uv

Step 2: Initialize your project

# If you don't have a pyproject.toml yet
uv init .

# This creates pyproject.toml without overwriting existing files

Step 3: Import your dependencies

# Import from requirements.txt
uv add -r requirements.txt

# Import dev dependencies
uv add --dev -r requirements-dev.txt

That's it. uv creates a pyproject.toml with your dependencies and a uv.lock file with the exact resolved versions. The lock file replaces requirements.txt for reproducibility.

Step 4: Use uv instead of pip from now on

# Old way
pip install requests
pip install -r requirements.txt
python -m venv .venv

# New way
uv add requests
uv sync
uv venv

The uv add command does what Poetry does — adds the package to pyproject.toml, resolves dependencies, updates the lock file, and installs everything. One command instead of three.

From pip to uv (Drop-in Mode)

If you're not ready for the full project workflow, uv has a pip-compatible interface:

# These work exactly like pip, just faster
uv pip install requests
uv pip install -r requirements.txt
uv pip freeze > requirements.txt

Same commands. Same behavior. Just 10-100x faster. No config changes needed.

From Flake8 + Black + isort to Ruff

Step 1: Add ruff to your project

uv add --dev ruff

Step 2: Create a minimal config

# pyproject.toml
[tool.ruff]
target-version = "py312"
line-length = 88

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # pyflakes
    "I",    # isort
    "B",    # flake8-bugbear
    "UP",   # pyupgrade
]

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

Step 3: Run it

# Lint and auto-fix
ruff check --fix .

# Format (replaces black)
ruff format .

Step 4: Remove the old tools

uv remove flake8 black isort pyupgrade autoflake

If you were using flake8 plugins, ruff has a migration guide that maps each plugin to its ruff rule code. The select list in your config is where you enable equivalent rule sets.


The pyproject.toml That Replaces Everything

Here's what a modern Python project config looks like in 2026:

[project]
name = "my-project"
version = "0.1.0"
description = "A modern Python project"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115.0",
    "sqlalchemy>=2.0",
    "httpx>=0.27",
]

[project.optional-dependencies]
dev = [
    "ruff>=0.15.0",
    "pytest>=8.0",
    "mypy>=1.14",
]

[tool.ruff]
target-version = "py312"
line-length = 88

[tool.ruff.lint]
select = ["E", "W", "F", "I", "B", "UP", "S", "D"]
ignore = ["D100", "D104"]

[tool.ruff.lint.isort]
known-first-party = ["my_project"]

[tool.ruff.format]
quote-style = "double"
docstring-code-format = true

One file. No setup.py. No setup.cfg. No .flake8. No pyproject.toml with three separate [tool.X] sections for three different formatters. No requirements.txt, requirements-dev.txt, requirements-prod.txt, constraints.txt.

Just pyproject.toml and uv.lock.


Who's Already Using This Stack

The adoption list is long:

Project / CompanyWhat They UseNotes
FastAPIRuffSwitched from Flake8 + Black
pandasRuffOne of the largest Python codebases
Apache AirflowRuffMassive CI time savings
pydanticRuffEarly adopter
Hugging FaceRuffML ecosystem leader
DjangoExploring uv + RuffCommunity momentum
OpenAI Codexuv1M minutes/week saved
Read the DocsMigrating to uvSwitch from pip requirements files

Microsoft uses uv and ruff in internal Python tooling. GitHub positions ruff as the default linter recommendation for new Python projects.

The pattern is clear: no major Python project that evaluates ruff goes back to flake8. The speed and simplicity gap is too wide.


The Elephant in the Room: OpenAI Bought Astral

On March 19, 2026, Astral announced it would join OpenAI. The Astral team moves into the Codex division.

The reaction was... not great.

Simon Willison captured the mood: the Hacker News thread hit 757 points and 475 comments in hours. Overwhelmingly anxious. The top concerns:

1. Corporate control over critical infrastructure. uv and ruff aren't optional preferences anymore. They're infrastructure that a significant chunk of the Python ecosystem depends on daily. That infrastructure now belongs to a company that reportedly spends $2.50 to make $1 in revenue.

2. Open source sustainability. OpenAI said they'll continue supporting Astral's open source products. But "plans to support" and "legally binding commitment" are different things. What happens when OpenAI needs to cut costs? When priorities shift?

3. The Python community can't fork effectively. uv and ruff are written in Rust. Most Python developers can't contribute to Rust codebases. If OpenAI ever abandons or restricts these tools, forking them requires Rust engineers, not Python ones.

Here's the thing though: this risk existed before the acquisition. Astral was VC-funded with no clear monetization path. The Python community was already depending on a company that burned investor money to build free tools. OpenAI just made the dependency explicit.

The tools are MIT/Apache-2.0 licensed. The code is on GitHub. If OpenAI does something stupid, the community can fork — it'll just need Rust developers to maintain the forks. That's a real constraint, but it's not a death sentence.


What Other Articles Get Wrong

Most "uv vs pip" articles miss three things:

1. uv is not just faster pip. Comparing uv to pip is like comparing VS Code to Notepad. Yes, VS Code opens files faster, but that's not the point. uv replaces pip, virtualenv, pyenv, pip-tools, Poetry, and pipx. The speed is the least interesting part. The interesting part is having one tool that does everything.

2. You don't have to go all-in. Every migration guide presents it as a binary: pip or uv. In practice, uv pip install is a drop-in replacement that requires zero config changes. You can use uv as "fast pip" for months before adopting pyproject.toml and uv lock. The official migration guide explicitly supports this gradual approach.

3. Ruff's formatting isn't identical to Black. It's 99.9% compatible, but there are intentional differences. The 2026 style introduced in v0.15.0 diverges further. If your team has strict "must match Black exactly" requirements, you'll need to verify. For everyone else, the differences are inconsequential.


The Honest Drawbacks

I'd be dishonest if I didn't mention the problems:

Legacy codebases can be painful. If your project has been running for 15 years on a pile of never-cleaned pip freeze exports with pinned versions of packages that no longer exist, uv's resolver may struggle. uv can't fix bad metadata on PyPI — that's not a uv problem, it's a PyPI ecosystem problem. But pip's looser resolution strategy sometimes "works" on broken dependency trees where uv correctly fails.

The Rust barrier is real. Python developers can't easily contribute to uv or ruff. Bug reports? Sure. Feature requests? Yes. But actual code contributions require Rust expertise. This locks out most of the Python community from the tools they depend on.

Configuration differences. If you've invested heavily in flake8 plugin ecosystems (custom rules, organization-specific plugins), ruff may not cover 100% of your setup. Most popular plugins are covered, but niche or custom ones aren't. Check the rule compatibility list before migrating.

The uv CLI is... evolving. Some command names and flags have changed between versions. If you pin uv to a specific version in CI (which you should), this is manageable. But it can be jarring when uv tool behaves differently after an update.


The Complete Toolchain: 2026 Edition

Here's what a modern Python development setup looks like:

# Install uv (one-time)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create a new project
uv init my-project
cd my-project

# Pin Python version
uv python pin 3.12

# Add dependencies
uv add fastapi uvicorn sqlalchemy
uv add --dev ruff pytest mypy

# Lint, format, test
ruff check --fix .
ruff format .
uv run pytest

# Run the project
uv run python -m my_project

And the CI equivalent:

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5

      - name: Install dependencies
        run: uv sync --frozen

      - name: Lint
        run: uv run ruff check .

      - name: Format check
        run: uv run ruff format --check .

      - name: Test
        run: uv run pytest

Notice: no actions/setup-python. uv manages the Python version itself. No pip install -r requirements.txt. uv sync --frozen installs exactly what's in uv.lock. The entire CI job runs in seconds, not minutes.


ty: The Missing Piece

Astral's newest tool is ty — a Python type checker, also written in Rust. It's designed to replace mypy and pyright with the same speed advantage that ruff brought to linting.

ty is still early (pre-1.0), but it integrates with ruff's configuration system and shares its philosophy: fast, opinionated, and configured through pyproject.toml. When ty stabilizes, the Astral stack will be:

  • uv — packages, environments, Python versions
  • ruff — linting and formatting
  • ty — type checking

Three tools. All Rust. All configured in pyproject.toml. All 10-100x faster than what they replace. That's the Python toolchain in 2026.


What I Actually Think

The Python tooling story has been embarrassing for years. Every other language — Go, Rust, JavaScript, even PHP — had a single, fast, official package manager. Python had pip, pip-tools, Poetry, pdm, hatch, flit, setuptools, easy_install (remember that one?), conda, mamba, and a dozen others. Configuration was split across setup.py, setup.cfg, pyproject.toml, requirements.txt, Pipfile, poetry.lock, and whatever else each tool invented.

uv and ruff didn't just make things faster. They made things simple. One tool for packages. One tool for code quality. One config file. That simplicity is more important than the speed, honestly. Speed is a bonus. Not having to Google "poetry vs pip-tools vs pdm" for the eighth time is the actual win.

I think the OpenAI acquisition is a net negative for the community. Not because OpenAI will definitely kill these tools — they probably won't, at least not soon. But because it concentrates power. The Python ecosystem's strength has always been its decentralized, community-driven nature. Having your package manager and linter owned by an AI company with a track record of broken promises about openness is... not ideal.

But here's my honest take: I'd still use uv and ruff today. Even knowing the risks. Because the alternatives are objectively worse. pip is slow. flake8's plugin system is fragmented. black and isort are two tools that should be one. Poetry is good but slower. The Astral tools are better by every measurable metric.

If OpenAI does something bad with these tools, the community will fork them. It'll be painful — Rust isn't Python, and finding maintainers will be hard. But the MIT license means the code can't be taken away. That's the safety net.

For new Python projects in 2026, there's no reason to start with anything other than uv + ruff. For existing projects, the migration is genuinely a 5-minute task for the drop-in pip replacement, and maybe an afternoon for the full pyproject.toml conversion. The ROI — faster CI, simpler config, fewer tools to maintain — is obvious from day one.

The old toolchain is dead. Not because anyone killed it, but because something better arrived. That's how it should work.


Sources

  1. OpenAI to acquire Astral — Official announcement
  2. Astral to join OpenAI — Astral blog
  3. Simon Willison — Thoughts on OpenAI acquiring Astral
  4. uv — PyPI
  5. Ruff — PyPI
  6. astral-sh/uv — GitHub
  7. astral-sh/ruff — GitHub
  8. Ruff documentation
  9. uv migration guide — From pip to a uv project
  10. Ruff FAQ — Astral docs
  11. Ruff v0.15.0 — Astral blog
  12. 2025 Stack Overflow Developer Survey
  13. Python in 2026: Why I Replaced pip with uv — DEV Community
  14. A year of uv: pros, cons, and should you migrate — Bite Code
  15. Best Python Developer Tools in 2026 — DEV Community
  16. Python Dependency Management in 2026 — Cuttlesoft
  17. uv + Ruff — The Fastest Python Workflow in 2026 — PyInns
  18. ty — Astral's Python type checker
  19. How to migrate from requirements.txt to pyproject.toml with uv — pydevtools
  20. From Flake8, isort, and Black to Ruff — Medium
  21. Read the Docs migration to uv — GitHub issue
  22. uv vs pip — Real Python
  23. OpenAI acquires Astral — ComputeLeap analysis