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:
| Tool | What It Did | uv Replacement |
|---|
| pip | Package installation | uv pip install or uv add |
| pip-tools | Dependency locking | uv lock |
| virtualenv / venv | Virtual environments | uv venv (80x faster) |
| pyenv | Python version management | uv python install |
| Poetry | Project management + locking | uv init + uv add + uv lock |
| pipx | Global tool installation | uv tool install |
| pip-compile | Requirements compilation | uv pip compile |
That's seven tools replaced by one. And the performance gap is absurd:
| Operation | pip / traditional | uv | Speedup |
|---|
| Package installation (warm cache) | 45-60s | under 5s | ~10x |
| Virtual environment creation | ~4s (venv) | ~0.05s | ~80x |
| Dependency resolution | 30-35s | under 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:
| Tool | What It Did | Ruff Replacement |
|---|
| Flake8 | Linting | ruff check |
| Black | Code formatting | ruff format |
| isort | Import sorting | ruff check --select I |
| pyupgrade | Python version upgrades | ruff check --select UP |
| autoflake | Remove unused imports | ruff check --select F401 |
| pydocstyle | Docstring linting | ruff check --select D |
| pyflakes | Error detection | Built-in |
| pycodestyle | PEP 8 checking | Built-in |
| Bandit | Security linting | ruff check --select S |
| flake8-bugbear | Bug detection | ruff 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:
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.
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
- OpenAI to acquire Astral — Official announcement
- Astral to join OpenAI — Astral blog
- Simon Willison — Thoughts on OpenAI acquiring Astral
- uv — PyPI
- Ruff — PyPI
- astral-sh/uv — GitHub
- astral-sh/ruff — GitHub
- Ruff documentation
- uv migration guide — From pip to a uv project
- Ruff FAQ — Astral docs
- Ruff v0.15.0 — Astral blog
- 2025 Stack Overflow Developer Survey
- Python in 2026: Why I Replaced pip with uv — DEV Community
- A year of uv: pros, cons, and should you migrate — Bite Code
- Best Python Developer Tools in 2026 — DEV Community
- Python Dependency Management in 2026 — Cuttlesoft
- uv + Ruff — The Fastest Python Workflow in 2026 — PyInns
- ty — Astral's Python type checker
- How to migrate from requirements.txt to pyproject.toml with uv — pydevtools
- From Flake8, isort, and Black to Ruff — Medium
- Read the Docs migration to uv — GitHub issue
- uv vs pip — Real Python
- OpenAI acquires Astral — ComputeLeap analysis