uv, the python package manager

A hipster python package manager with handy features for my workflow

2024-11-18 — 2026-10-03

quality 7.5

Wherein a Python Package Manager Is Fashioned by Astral, Script Dependencies Are Pinned via PEP 723, GPU-based PyTorch Indices Are Navigated, and a Bespoke Fish Shell Completion Is Required for Entry Points.

computers are awful
python
standards
Figure 1

uv is “an extremely fast Python package and project manager, written in Rust.” I classify it as a pip-like package manager, and moreover, the best package manager for most new projects.

It’s getting strong reviews, e.g., Loopwerk’s one.. The source is available at astral-sh/uv.

Claimed highlights:

uv is backed by Astral, the creators of Ruff.

Notably, uv has deep, highly specific pytorch support, so if you are doing ML on the GPU, this might be a great choice.

One thing it does not provide is a build back-end; we need to choose one. Who knew that was a thing? I didn’t know there was a build-front-end versus build-backend distinction.

1 Installation

We can install uv many ways. I prefer pipx on Linux and homebrew on macOS, but that’s just a matter of taste. The creators recommend

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

1.1 Shell completions

Baseline UV shell completions require manual intervention.:

# Determine your shell (e.g., with `echo $SHELL`), then run one of:
echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
echo 'uv generate-shell-completion fish | source' >> ~/.config/fish/config.fish

Annoyingly, uv will not autocomplete project entry points, so e.g. uv run will not autocomplete with the list of permissible scripts.

The following hack allows me to get tab-completion for uv run in fish shell. Bash users, let me know if you have a bash solution.

function __fish_uv_run_completions
    # `uv run` with no command prints the available entry points as "- name" lines.
    # Keep only those lines and strip the "- " prefix.
    # Append a tab-separated description so fish tags these in the pager.
    uv run 2>/dev/null | string replace -rf '^- (\S+)$' '$1\tenv command'
end

complete -c uv -n '__fish_seen_subcommand_from run' -a '(__fish_uv_run_completions)'

Add to ~/.config/fish/completions/uv.fish and then source ~/.config/fish/completions/uv.fish.

2 uv project setup

uv requires us to specify a build system in the pyproject.toml file if we want to “install” the package we are currently working on (e.g. do relative imports, have sub-folders in the source tree…). It does not provide one per default. To get one, create the project as one of the following:

uv init --package --build-backend hatch

If the env is already created, we need to add the build system manually into pyproject.toml; some useful ones are included.

Alternatively, we can set tool.uv.package = true in pyproject.toml.

Want to pretend to be running classic venv? You are looking for the command:

uv venv --python 3.12 # or other version

uv does not refresh version and download updated dependencies per default. To get that behaviour, we need to use the --upgrade flag:

uv sync --upgrade
Tiprun things without installing

uvx

The uvx command invokes a tool without installing it.[…] Tools are installed into temporary, isolated environments when using uvx.

3 standalone scripts

uv implements the Python Inline script metadata (PEP 723) standard, including inline dependencies, the #!/usr/bin/env -S uv run --script shebang, and pinning with uv lock --script.

Some related commands:

  • uv init --script foo.py creates the header for you.
  • uv add --script foo.py requests adds a dependency to the header.
  • uv run --with pymupdf foo.py adds a dependency for a single run without any header at all.
  • exclude-newer = "2026-01-01" under [tool.uv] in the header pins dependency resolution to packages released before that date, ensuring the script remains reproducible in a neat, minimalist, and human-friendly way.

NB: pipx run and hatch run read the same block, so the script isn’t tied to uv.

4 Migrating to uv from other systems