
Hook: Picking a Python package manager in 2026 isn't settled science yet — and the gap between the fastest and slowest option is bigger than most people assume.
If you started a Python project any time before 2024, you probably reach for pip and requirements.txt out of habit. If you started one in the last year, you've probably heard someone insist you switch to uv. And if you work on an existing codebase, there's a good chance it's locked into Poetry already. All three are legitimate choices today. They are not, however, equivalent — the differences show up the moment you actually set up the same project three ways.
Setting up the same project three ways
Here's the same tiny project — a FastAPI service with two dependencies — bootstrapped with each tool, using nothing but each tool's own defaults.
uv
uv init demo-project
cd demo-project
uv add fastapi uvicornThat's it. uv init writes a pyproject.toml and a .python-version. uv add resolves the dependency graph, writes it to uv.lock, and creates (or reuses) a .venv automatically — you never ran venv or pip install yourself.
Poetry
poetry new demo-project
cd demo-project
poetry add fastapi uvicornpoetry new scaffolds a pyproject.toml plus a package directory and a tests/ folder. poetry add resolves dependencies, updates pyproject.toml, and writes poetry.lock — also managing its own virtualenv under the hood, in a separate location unless you've configured virtualenvs.in-project.
pip + pip-tools
mkdir demo-project && cd demo-project
python -m venv .venv
source .venv/bin/activate
pip install pip-tools
cat > requirements.in <<EOF
fastapi
uvicorn
EOF
pip-compile requirements.in
pip install -r requirements.txtNotice what's missing here compared to the other two: nothing scaffolded the project structure, nothing created the venv for you, and there's no single command that both resolves and installs — you compile a lockfile, then separately install from it. pip-tools gets you reproducibility, but you're wiring the pieces together yourself.
What actually lands in the lockfile
This is where the real behavioral differences are, and it's also where most comparisons stay too vague to be useful. Here's what each lockfile actually commits to:
uv.lock— one file, plain TOML, and it's a universal lock: it resolves and records compatible versions across platforms and Python versions in the same file, with per-platform markers, so the same lockfile works whether a teammate is on Linux, macOS, or Windows. You check this single file into the repo.poetry.lock— also one file, also checked in, but it's resolved against whatever environment markers Poetry's resolver determined matter for your declared Python version constraint. It records exact versions and file hashes for every package. Regenerating it after a manualpyproject.tomledit requirespoetry lock— Poetry won't silently let the two drift, it errors out until you resync them.requirements.txt(via pip-compile) — flat, pinned, optionally hashed withpip-compile --generate-hashes. There's no automatic re-check against a source-of-truth file the way Poetry enforces one — if you hand-editrequirements.txtinstead ofrequirements.in, nothing stops you, and nothing warns you the two have diverged.
The practical upshot: uv and Poetry both give you a self-consistent, enforced lock. pip-tools gives you a lock, but the discipline to keep it honest is entirely on you and your CI checks.
Install speed: what the numbers actually say
uv is written in Rust, uses a global content-addressable cache shared across all your projects (so a package you've already downloaded for one project doesn't get re-downloaded for the next), and parallelizes resolution and downloads. Astral, the team behind uv, has published benchmark numbers showing installs roughly an order of magnitude faster than pip on a warm cache, and faster still relative to pip on a cold cache — with Poetry landing somewhere in between pip and uv, since Poetry's resolver is also more sophisticated than pip's legacy one but is implemented in Python rather than Rust.
The mechanism matters more than the exact multiplier: pip's resolver (the modern backtracking one, not the old flat installer) re-resolves from scratch more often and doesn't share a cache across projects the way uv does by default. On a large dependency tree, that difference compounds — it's not just download time, it's resolver time too.
Dependency resolution: who actually gets it right
uv and Poetry both use resolvers based on PubGrub, the same resolution algorithm family used by Dart's package manager — it's designed to produce clear, explainable conflict errors instead of pip's historically opaque "no versions found that satisfy" dead ends. pip's resolver, since the 2020 rewrite, also does real backtracking now — it's no longer the first-match-wins installer it used to be — but it still doesn't maintain a persistent lockfile on its own; that's what pip-tools bolts on.
In practice, if you've ever fought a Poetry or uv resolver that got stuck on a transitive conflict, read the error message — both tools tell you exactly which two packages disagree and why, which is a genuinely different debugging experience than tracing a pip install failure by hand.
The verdict for 2026
For a brand-new project with no existing tooling commitments: start with uv. The combination of one fast tool for venv + resolve + lock + run, a universal lockfile, and a shared cache across projects removes friction that the other two still have you managing by hand.
Stick with Poetry if you're already on it and it's working — the migration isn't free, and Poetry's resolver and lockfile guarantees are genuinely solid, not a liability. Reach for plain pip + pip-tools only when you need the absolute minimum dependency footprint in your tooling itself, like a constrained CI image where even installing uv or Poetry is unwanted overhead.
Try it on your own project. Pick a real repo you maintain, run uv init in a throwaway copy, and compare the resulting uv.lock against whatever you're using today — the lockfile diff alone tells you more than any benchmark chart will.

Experienced DevOps Engineer proficient in Python, Docker, Kubernetes, CI/CD, and cloud technologies. Specialized in automating processes and building scalable infrastructure for seamless development and deployment.


