UV Cheatsheet

UV is a Python package manager written in Rust by Astral (same team as ruff). It replaces pip, pip-tools, virtualenv, pyenv, poetry, and pipx, and is 10-100x faster than pip.

Why UV

  • Speed: 10-100x faster than pip. Cold installs in seconds, warm installs near-instant via cache.
  • One tool: replaces pip, pip-tools, virtualenv, pyenv, poetry, pipx.
  • uv.lock: deterministic lockfile, reproducible across machines.
  • No Python required to install: UV is a single binary, manages its own Python downloads.

Installation

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

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# Homebrew
brew install uv

# pip (if you already have it)
pip install uv

# Verify
uv --version

Project Management

Replaces poetry / pip + requirements.txt.

# Create a new project (generates pyproject.toml + .python-version + uv.lock)
uv init myproject
cd myproject

# Create a library (src layout)
uv init --lib mylib

# Add a dependency
uv add requests
uv add "fastapi>=0.100"
uv add "torch==2.3.0"

# Add a dev dependency
uv add --dev pytest ruff mypy

# Remove a dependency
uv remove requests

# Install all deps from lockfile (what you run after git clone)
uv sync

# Install without updating lockfile (strict, for CI)
uv sync --frozen

# Update lockfile without installing
uv lock

# Update a specific package
uv lock --upgrade-package requests

# Update all packages
uv lock --upgrade

# Run a command in the project environment
uv run python main.py
uv run pytest
uv run -- python -c "import sys; print(sys.version)"

pyproject.toml structure

[project]
name = "myproject"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "requests>=2.31",
    "fastapi>=0.100",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "ruff>=0.4",
    "mypy>=1.10",
]

[tool.uv]
dev-dependencies = [
    "pytest>=8.0",
    "ruff>=0.4",
]

Python Version Management

Replaces pyenv.

# Install a Python version
uv python install 3.12
uv python install 3.11 3.12 3.13

# List available (installed + downloadable)
uv python list
uv python list --all-versions

# Pin the project to a Python version (creates .python-version)
uv python pin 3.12

# Find a Python binary
uv python find 3.12

# Find the active Python
uv python find

UV downloads and manages Python builds from python-build-standalone. They live in ~/.local/share/uv/python/.

Virtual Environments

Replaces virtualenv / python -m venv.

# Create .venv in current directory
uv venv

# Specific Python version
uv venv --python 3.12

# Custom path
uv venv /tmp/myenv

# Activate (Linux/macOS)
source .venv/bin/activate

# Activate (Windows PowerShell)
.venvScriptsActivate.ps1

# Deactivate
deactivate

When you run uv sync or uv run inside a project, UV automatically creates and uses .venv without you needing to activate it.

pip Interface

Drop-in replacement for pip. Works inside or outside a project.

# Install packages
uv pip install requests
uv pip install "fastapi[standard]>=0.100"
uv pip install -r requirements.txt
uv pip install -e .                    # editable install
uv pip install ".[dev]"               # with extras

# Uninstall
uv pip uninstall requests

# List installed packages
uv pip list
uv pip list --outdated

# Show package info
uv pip show requests

# Freeze (output pinned requirements)
uv pip freeze
uv pip freeze > requirements.txt

# Compile requirements.in to pinned requirements.txt
uv pip compile requirements.in -o requirements.txt
uv pip compile requirements.in -o requirements.txt --upgrade

# Sync environment to exact requirements.txt (removes extra packages)
uv pip sync requirements.txt

Inline Script Dependencies (PEP 723)

Run scripts with dependencies without creating a project.

# script.py
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "requests",
#   "rich>=13",
# ]
# ///

import requests
from rich import print

r = requests.get("https://api.github.com")
print(r.json())
# UV reads the inline metadata and installs deps automatically
uv run script.py

# Pass extra deps at runtime
uv run --with pandas script.py

No pip install, no venv, no requirements.txt. UV caches the environment and reuses it.

Tool Management

Replaces pipx.

# Install a tool globally (isolated environment)
uv tool install ruff
uv tool install black
uv tool install httpie

# Run a tool without installing (ephemeral)
uv tool run ruff check .
uv tool run --with "ruff==0.4.0" ruff check .

# Shorthand: uvx = uv tool run
uvx ruff check .
uvx black .
uvx pytest

# List installed tools
uv tool list

# Upgrade a tool
uv tool upgrade ruff
uv tool upgrade --all

# Uninstall
uv tool uninstall ruff

Tools are installed in ~/.local/share/uv/tools/ and their binaries are linked to ~/.local/bin/.

Workspaces (Monorepo)

# Root pyproject.toml
[tool.uv.workspace]
members = ["packages/*"]

[tool.uv.sources]
mylib = { workspace = true }
# Sync a specific package
uv sync --package mylib

# Run in a specific package context
uv run --package mylib pytest

Common Workflows

Start a new project

uv init myproject
cd myproject
uv python pin 3.12
uv add fastapi uvicorn
uv add --dev pytest ruff mypy
uv run python -c "print('hello')"

After cloning an existing project

git clone https://github.com/user/repo
cd repo
uv sync          # creates .venv, installs all deps from uv.lock
uv run pytest

Migrate from pip + requirements.txt

uv init
# Copy your dependencies into pyproject.toml manually, or:
uv add $(cat requirements.txt | grep -v "^#" | tr "\n" " ")
uv sync

Migrate from poetry

# UV reads pyproject.toml directly, poetry deps are compatible
# Just replace: poetry install -> uv sync
# poetry add X    -> uv add X
# poetry run X    -> uv run X
# poetry shell    -> source .venv/bin/activate (after uv sync)

CI/CD (GitHub Actions)

- name: Install uv
  uses: astral-sh/setup-uv@v5
  with:
    uv-version: "latest"
    enable-cache: true

- name: Install dependencies
  run: uv sync --frozen

- name: Run tests
  run: uv run pytest

- name: Lint
  run: uv run ruff check .

--frozen ensures CI uses exactly what is in uv.lock, no surprises.

Configuration

# Clear cache (free disk space)
uv cache clean

# Remove unused cache entries
uv cache prune

# Show cache directory
uv cache dir

# Skip cache for a command
uv sync --no-cache

Environment variables

UV_CACHE_DIR=~/.uv/cache        # Override cache location
UV_PYTHON=3.12                  # Override Python version
UV_NO_CACHE=1                   # Disable cache
UV_SYSTEM_PYTHON=1              # Allow using system Python
UV_PROJECT_ENVIRONMENT=.venv    # Override venv path

uv.toml (project-level config)

[tool.uv]
python = "3.12"
dev-dependencies = ["pytest", "ruff"]

# Pin index
index-url = "https://pypi.org/simple"
extra-index-url = ["https://download.pytorch.org/whl/cu121"]

# Exclude from lockfile resolution
constraint-dependencies = ["numpy<2"]

Quick Reference

Task Old way UV
Install package pip install X uv pip install X or uv add X
Install from requirements pip install -r req.txt uv pip install -r req.txt
Create virtualenv python -m venv .venv uv venv
Install Python 3.12 pyenv install 3.12 uv python install 3.12
Init project poetry init uv init
Add dependency poetry add X uv add X
Add dev dependency poetry add -D X uv add --dev X
Install all deps poetry install uv sync
Run in env poetry run X uv run X
Lock deps poetry lock uv lock
Install global tool pipx install ruff uv tool install ruff
Run tool once pipx run ruff . uvx ruff .
Compile requirements pip-compile req.in uv pip compile req.in
Freeze pip freeze uv pip freeze

Why It’s Fast

UV uses:

  • Rust: no GIL, true parallelism for dependency resolution
  • Parallel downloads: fetches multiple packages simultaneously
  • Global cache: packages are cached globally and hard-linked into venvs (near-zero copy cost)
  • PubGrub solver: faster dependency resolution algorithm than pip’s
  • No subprocess overhead: everything runs in-process