UV for python dependencies

guide
Python
Author

im@johnho.ca

Published

Friday, May 2, 2025

Abstract
the GOAT of python dependencies management, at least as of 2025

why uv?

three simple answers:

  1. it’s fast1
  2. if it’s good enough for streamlit cloud it’s good enough for me
  3. good for packaging2 and virtual environments are stored in project directories

installation

macOS and Linux: curl -LsSf https://astral.sh/uv/install.sh | sh

Or pipx install uv

confirm the installation with uv --version

python versions

uv manages it’s own python versions much like pyenv

use uv python list to view installed and available python version and uv python install 3.8 to install a specific version3.

Virtual Environments

unlike pyenv4, when you run uv venv5 an environment will be created in your current working directory in .venv this allows you to keep each project’s dependencies isolated. To activate the environment just source .venv/bin/activate. And to deactivate, just deactivate.

To install just append uv in front of your standard pip install command. For example, uv pip install -r requirements.txt and to see what’s installed, uv pip list. Commands such as these that mutates environments will always applied in the following order:

  1. the activated environment
  2. the environment at .venv in the current directory

Tools

Tools are python packages with a CLI

In most cases, executing a tool with uvx is more appropriate than installing the tool.

When running a tool with uvx, a virtual environment is stored in the uv cache directory and is treated as disposable, i.e., if you run uv cache clean the environment will be deleted.

Existing Projects

because of the tools feature, you can call the migrate-to-uv package on your existing project to have uv manage the dependencies (no installation required ;):

uvx migrate-to-uv

you can add the --dry-run flag to see what it would do but basically it will read your requirements.txt (and also removes it) and create a pyproject.toml6 and a uv.lock file7 for your project.

and if you need to export the environment back to requirements.txt you could8:

uv export --no-hashes --format requirements-txt > requirements.txt

New Projects

you can run uv init new-project to have uv create everything for you.

there are a few different variations:

  • an Application
    • great for writing scripts, web services, and CLI tools
    • it’s the default when you run uv init example-app (the --app flag is implied)
  • a Package: for things that are mean to be “pip-installable”
    • Application
      • running uv init --package example-pkg will create a setup with a build system and command definition.
    • Library
      • library provides functions and objects for other projects to import
      • can be created with uv init --lib example-lib (--lib implies --package)
      • a build system is defined but not a command definition

a minimal project

using the --bare flag gives you the most basic project structure. Here’s an example:

mkdir new-project
cd new-project
uv init --bare              # this only creates pyproject.toml
uv venv --python 3.12       # this creates an environment at .venv using python 3.12
uv add awesome-package1     # add your project's requirements

References

Footnotes

  1. about 115x faster than pip, in the time it takes to run pip install on your next project you can probabaly read this post and learn all the basics to get started.↩︎

  2. when you uv remove something, no dangling packages are left behind, you can inspect after with uv tree↩︎

  3. add export UV_PYTHON_INSTALL_DIR=$HOME/your/custom/home/for/.uv/python/ to your ~/.bashrc to control where those managed python versions get installed to↩︎

  4. pyenv’s virutal environment are installed by default to ~/.pyenv/versions/<env-name>/↩︎

  5. or use uv venv --python 3.12 to create a virtual environment with python 3.12↩︎

  6. for an existing project, you might want to update the value for name and also add the requires-python field (with a value like >=3.8)↩︎

  7. the lockfile contains the exact resolved versions that are installed in the project environment and is meant to be checked into version control; So that it can be easily recreated else where with a uv sync↩︎

  8. see this stackoverflow answer for details↩︎

Reuse