uv Exposure

Patrick McCann
Friday 13 February 2026

Look at the installation instructions for most Python packages and you will typically be told to run pip install <package-name>. pip is the standard package manager for Python, generally available wherever Python is installed, and it’s what I’ve tended to use for managing python packages, alongside venv for creating virtual environments. I was aware that other package managers existed, particularly conda, which is the one referenced in the Software Carpentry Python setup instructions.

It was at a session at RSECon25 in September 2025 that I first heard about uv. I was aware that pip isn’t a hugely sophisticated tool, but I hadn’t been particularly motivated to look for an alternative. The session piqued my interest, and shortly afterwards I had a look at migrating an existing project from pip and venv to uv, but gave it up (after not very long, admittedly) as not worth the effort.

However, I recently started a new Python project and decided to use uv from the start. There are a few things that I like about it.

Firstly, and the thing which attracted me the most in the first place, is the better dependency management. The pyproject.toml and uv.lock combination provide a more robust way of managing dependencies, ensuring consistency across different environments, not least because they are automatically kept up to date as packages are installed – there’s no need for an equivalent to pip freeze > requirements.txt. It also has awareness of direct and indirect dependencies, which makes it easier to keep track of that’s being used and why, and it allows for development dependencies to be specified separately. These are all improvements over the standard pip/requirements.txt setup.

Secondly, I like the user interface. It’s a small thing, but project setup is very quick. The following commands are what I would have done previously:

mkdir my-project
cd my-project
git init
python -m venv .venv

With uv it’s just:

uv init my-project
cd my-project

And that actually does a bit more, creating a README etc. As already noted, there’s no need for an extra step to record dependencies after they’ve been installed. Also, the uv commands are aware of the virtual environment, so there’s no need to activate it first. When running other commands that need to be run using the venv, they are executing using uv run -- <cmd> – a bit more typing, but it makes it clear that the venv is in use.

Possibly the biggest difference is speed. I was aware that uv was faster than pip, but I hadn’t appreciated the difference it makes. It doesn’t matter much when installing packages during development, but it makes a huge difference when running CI pipelines. The setup of the environment and the installation of dependencies is often the slowest part of a CI pipeline and, in my experience at least, there’s always a part of the development where you’re repeatedly tweaking the CI configuration to try and get it right. At that point, having a pipeline that takes seconds rather than minutes makes that process much less frustrating.

One thing that did catch me out was that uv typically installs it’s own instance of the Python interpreter in the virtual environment. This allows you to control which version of Python is used, but it means that if you want to stick to the system Python, you need to specify that in pyproject.toml:

[tool.uv]
python-preference = "only-system"

In my case, I was running a web application on a server, and I wanted to stick to the system Python for security reasons.

I’m not sure if I’m a confirmed uv user, but I will continue to evaluate it as I use it more. I suspect that the speed alone would make it difficult to go back to pip.


Leave a reply

By using this form you agree with the storage and handling of your data by this website.