There are at least nine tools in the Python ecosystem that deal with some combination of “install a package” and “don’t break everything else.” Nine. And they all do slightly different things, with slightly different opinions, and slightly overlapping scopes. If you’ve ever stared at a blog post titled “Poetry vs. Pipenv vs. PDM” and felt your soul leave your body — yeah. Same.
Then uv showed up and said “what if one tool just… did most of it.” And the wild part is, it actually delivers.
First, though — how we ended up with a zoo in the first place.
The zoo, explained
Every one of these tools exists because something was missing. They grew organically, each filling a gap left by the last. The problem is that “organic growth” in tooling ecosystems produces roughly the same result as organic growth in a kitchen junk drawer.
pip is the original. It installs packages. That’s it. It does not lock dependencies, manage environments, or care about reproducibility. You say pip install flask, it installs Flask and whatever version of Werkzeug it feels like that day. Pip is a hammer, and for a long time it was the only hammer.
pip-tools (specifically pip-compile) exists because pip doesn’t lock. You give it your top-level requirements, it resolves everything, pins every version, writes a lockfile. Now your deploys are reproducible. It’s a thin, elegant layer on top of pip — and the fact that it needs to exist at all tells you something.
virtualenv and venv create isolated environments so your projects don’t stomp on each other’s dependencies. venv ships with Python since 3.3. virtualenv is the older, more featureful third-party version. They both do the same thing: give you a directory with its own site-packages. The fact that there are two of them is very on-brand for this ecosystem.
pyenv manages Python versions. Not packages — the interpreter itself. Need 3.11 for one project and 3.12 for another? pyenv. It compiles Python from source, shims your shell, and generally works great until it doesn’t. Notably, it has nothing to do with pip or packages. Completely orthogonal concern, completely separate tool.
pipx installs Python CLI tools globally — think black, ruff, httpie. Each tool gets its own isolated environment so they can’t conflict. It’s pip + virtualenv + “put it on my PATH,” packaged into a single command. A nice tool solving a real problem that arguably shouldn’t need its own tool.
Poetry said “enough of this” and tried to be the One Tool. Project init, dependency resolution, lockfiles, virtual environments, building, publishing — all in one. It has opinions, and they’re mostly good. The resolver is slow but correct. The pyproject.toml integration is solid. Poetry is what happens when someone looks at the JavaScript ecosystem’s npm and says “we should have that.”
PDM is similar to Poetry but with different opinions — PEP 582 support, a different resolver, a different lockfile format. It’s good. The fact that it exists alongside Poetry is, again, very Python.
Conda is the weird one. It’s not really a pip replacement — it’s a completely parallel package ecosystem. Conda packages native binaries: CUDA, MKL, libpng, things that have nothing to do with Python. It manages environments and Python versions and non-Python dependencies. Scientists love it because pip install numpy doesn’t link against your GPU, but conda install pytorch does. It’s powerful and heavy and its own universe.
Enter uv
uv is written in Rust by the Astral team (the Ruff people). It’s fast — not “a little faster,” but 10-100x faster than pip in most benchmarks. Cold installs that took 30 seconds now take 2.
Speed is the headline, but the real story is scope. uv quietly absorbed almost every tool above:
| What you used to do | Old tool | uv equivalent |
|---|---|---|
| Install packages | pip | uv pip install |
| Lock dependencies | pip-compile | uv pip compile |
| Install CLI tools globally | pipx | uv tool install / uvx |
| Manage Python versions | pyenv | uv python install |
| Create virtual environments | virtualenv / venv | uv venv |
| Project management + lockfile | poetry / pdm | uv init / uv add / uv lock / uv sync |
That’s six tools replaced by one binary with no Python dependency. You don’t even need Python installed to use uv — it’ll download it for you.
Why this works
The Python packaging mess isn’t about bad tools. Each tool is fine. The mess is combinatorial — you need to know which subset to combine, in what order, with what configuration, for your specific use case. “I just want to start a project” requires choosing between pyenv + venv + pip-tools, or Poetry, or PDM, or conda, and every choice has tradeoffs you won’t understand until six months in.
uv collapses the decision tree. One tool. One install. If you’re starting a new project: uv init, uv add flask, uv run python app.py. It creates the venv, resolves dependencies, writes the lockfile, and runs your code. No choosing. No wiring tools together.
The uv pip commands are there for compatibility — if you’re migrating from an existing pip-tools workflow, you don’t have to change everything at once. But the real interface is the project commands: uv init, uv add, uv sync, uv lock, uv run. That’s your day-to-day.
The one thing uv doesn’t replace
Conda.
uv operates in pip-land — it installs Python packages from PyPI. It cannot install system-level native libraries. If you need CUDA toolkit, or a specific BLAS implementation, or any of the gnarly compiled-from-C-and-Fortran stuff that data scientists depend on — uv won’t help. Conda’s superpower is packaging everything, not just Python, and nothing in the pip ecosystem (uv included) has solved that.
If your world is web apps, CLIs, and pure Python — uv covers you completely. If your world involves GPUs and linear algebra, you’ll probably still want conda for the native bits, and uv for everything else.
So what now
If you’re starting fresh, just use uv. Seriously. curl -LsSf https://astral.sh/uv/install.sh | sh and go. You can learn the rest of the zoo later if you need to — but you probably won’t.
The Python packaging ecosystem spent fifteen years building nine tools that each do one-third of the job. uv does the whole job, in one binary, faster than any of them.
Sometimes the answer really is “rewrite it in Rust.”