I’ve switched to uv for all of my Python projects—both legacy and new—over the past year. It offers many interesting features, but I’ve narrowed it down to three that make it an absolute joy to use.

It can manage Python versions

Not only UV can install dependencies, but can also install Python (-s). Great dev-ex, one command for both. An example - I constantly switch between 3 Python apps, all with different Python versions. With UV, I can go to project’s dir, run:

uv run pytest tests

and it installs / switches to project's Python. Infers straight from pyproject.toml:

[project]
requires-python = ">=3.12,<3.14"

uv run will pull-in Python 3.13, at most. No need for a separate tool like pyenv, on top pyenv does not understand pyproject.toml’s Python.

It is fast

Faster than pip, or frankly any package manager. It feels real-time. Because of Rust™. Speed is rarely a tradeoff (from a user point of view).

It can spin-up virtual envs on the fly (the script mode)

A year ago I thought this one was a killer feature. Putting it last though, I barely used it a few times. Nonetheless, it’s cool. Here’s a situation I had - I was debugging some parallel http calls, it was convenient to just run the script with:

uvx --python 3.13 --with pandas test_concurrent_calls.py

Pulled-in Py13 + Pandas. Slight difference from a year ago - change uv -> uvx, to leave no venv trace. Neat, right?

Cons?

I’ve yet to find any. Once I couldn’t install some Torch dependency because UV kept insisting incompatibility with my system. That’s useful though, but I knew what I was doing and got blocked. Conda packages? Unsupported, but didn’t need those, at least for production apps.

To another year - now, please improve (speed of) type checking 🐍.