uv
Overview
uv is a modern Python package and project manager from Astral, written in Rust and designed to be 10–100x faster than pip. It provides a unified interface for managing Python versions, virtual environments, project dependencies, lockfiles, and standalone tools — replacing pip, pip-tools, pipx, poetry, pyenv, and virtualenv in one binary.
Installation
Linux / macOS (recommended)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or via pip
pip install uv
Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Homebrew (macOS / Linux)
brew install uv
Verify installation
uv --version
uv self update # Update uv itself
Configuration
Environment variables
UV_PYTHON=3.12 # Default Python version
UV_CACHE_DIR=~/.cache/uv # Custom cache location
UV_NO_CACHE=1 # Disable caching
UV_INDEX_URL=https://pypi.org/simple # Custom index
UV_EXTRA_INDEX_URL=https://my.pypi.org/simple # Additional index
UV_SYSTEM_PYTHON=1 # Allow using system Python
UV_LINK_MODE=copy # hardlink | symlink | copy | clone
uv.toml (project-level config)
[tool.uv]
python = "3.12"
index-url = "https://pypi.org/simple"
[[tool.uv.index]]
name = "internal"
url = "https://internal.company.com/simple"
pyproject.toml integration
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.110",
"httpx>=0.27",
]
[project.optional-dependencies]
dev = ["pytest", "ruff"]
[tool.uv]
dev-dependencies = ["pytest>=8", "ruff>=0.4"]
Core Commands
| Command | Description |
|---|---|
uv init my-project | Create a new project with pyproject.toml |
uv add requests | Add a dependency and update lockfile |
uv add --dev pytest | Add a dev dependency |
uv remove requests | Remove a dependency |
uv sync | Install all dependencies from lockfile |
uv lock | Generate/update uv.lock without installing |
uv run python script.py | Run script in project virtual environment |
uv run pytest | Run a command in the project environment |
uv pip install requests | pip-compatible install |
uv pip compile requirements.in | Compile requirements like pip-tools |
uv pip sync requirements.txt | Sync environment to requirements file |
uv venv | Create a virtual environment |
uv python install 3.12 | Download and install Python 3.12 |
uv python list | List available Python versions |
uv python pin 3.11 | Pin project to Python version |
uv tool install ruff | Install a CLI tool globally |
uv tool run ruff check . | Run a tool without installing |
uvx ruff check . | Shorthand for uv tool run |
uv tree | Show dependency tree |
uv export | Export dependencies to requirements.txt |
Advanced Usage
Python version management
# Install specific Python versions
uv python install 3.11 3.12 3.13
# List installed and available versions
uv python list
# Pin a project to a version (writes .python-version)
uv python pin 3.12
# Use a specific version for a command
uv run --python 3.11 python --version
# Find the Python interpreter uv would use
uv python find 3.12
Virtual environment control
# Create venv in default .venv/
uv venv
# Create venv with specific Python
uv venv --python 3.12
# Create venv in custom location
uv venv /path/to/myenv
# Activate (standard shell activation still works)
source .venv/bin/activate
# Or just use uv run to avoid activating
uv run python -c "import sys; print(sys.version)"
Lockfile and reproducible builds
# Generate lockfile without installing
uv lock
# Install exactly what's in the lockfile
uv sync --frozen
# Check lockfile is up-to-date (CI use)
uv lock --check
# Export to pip-compatible requirements
uv export --format requirements-txt > requirements.txt
uv export --no-hashes > requirements.txt
uv export --only-dev > dev-requirements.txt
Workspace (monorepo) support
# Root pyproject.toml
[tool.uv.workspace]
members = ["packages/*"]
# Sync entire workspace
uv sync --all-packages
# Sync a specific member
uv sync --package my-lib
Dependency groups and extras
# Add with extras
uv add "fastapi[standard]"
# Sync with optional extras
uv sync --extra all
# Add to a named group
uv add --group lint ruff mypy
# Sync only specific groups
uv sync --group dev --group lint
Tool management (replaces pipx)
# Install tool globally
uv tool install ruff
uv tool install black
uv tool install httpie
# List installed tools
uv tool list
# Run a tool without permanent install
uvx cowsay "hello"
# Upgrade a tool
uv tool upgrade ruff
# Uninstall a tool
uv tool uninstall ruff
# Install specific version of a tool
uv tool install ruff==0.4.0
Advanced pip interface
| Command | Description |
|---|---|
uv pip install -r requirements.txt | Install from requirements file |
uv pip install -e . | Editable install |
uv pip install --index-url URL pkg | Install from custom index |
uv pip list | List installed packages |
uv pip show requests | Show package details |
uv pip freeze | Output installed packages |
uv pip check | Check for dependency conflicts |
uv pip uninstall requests | Uninstall a package |
uv pip compile pyproject.toml -o requirements.txt | Compile dependencies |
uv pip sync requirements.txt | Sync environment exactly |
Common Workflows
Starting a new project
# Initialize project
uv init my-api
cd my-api
# Add dependencies
uv add fastapi uvicorn httpx
uv add --dev pytest pytest-asyncio ruff
# Run the application
uv run uvicorn main:app --reload
# Run tests
uv run pytest
Migrating from pip / requirements.txt
# Convert requirements.txt to pyproject.toml-managed project
uv init --no-readme
uv add $(cat requirements.txt | grep -v '^#' | tr '\n' ' ')
# Or keep using requirements.txt with uv's pip interface
uv pip install -r requirements.txt
Migrating from poetry
# uv reads pyproject.toml natively
# Just replace `poetry install` with:
uv sync
# Replace `poetry add X` with:
uv add X
# Replace `poetry run X` with:
uv run X
CI/CD (GitHub Actions)
- uses: astral-sh/setup-uv@v5
with:
version: "latest"
enable-cache: true
- name: Install dependencies
run: uv sync --frozen
- name: Run tests
run: uv run pytest
Docker usage
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev
COPY . .
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0"]
Scripting with inline dependencies
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["httpx", "rich"]
# ///
import httpx
from rich import print
data = httpx.get("https://api.github.com").json()
print(data)
uv run my_script.py # uv installs deps automatically
chmod +x my_script.py && ./my_script.py
Tips and Best Practices
Commit the lockfile. Always commit uv.lock to version control for reproducible installs across your team and CI.
Use uv sync --frozen in CI. This fails if the lockfile is out of date, preventing accidental dependency drift in production.
Prefer uv run over activating the venv. Running uv run pytest instead of activating .venv is more portable and works in scripts without shell magic.
Cache in CI. Use astral-sh/setup-uv with enable-cache: true for fast GitHub Actions runs. uv caches downloaded wheels and metadata aggressively.
Use uvx for one-off tools. Instead of globally installing linters or generators just to run them once, use uvx ruff check . — it downloads, caches, and runs without polluting your environment.
Separate dev dependencies from production. Use uv add --dev or --group to keep production images lean. Then uv sync --no-dev in Docker.
Pin Python version in .python-version. Run uv python pin 3.12 to create this file so all teammates and CI use the same interpreter without extra config.
Use workspaces for monorepos. If you have multiple related packages, uv workspaces let you share a single lockfile and avoid duplicating dependencies.
Check for outdated packages. Use uv tree --outdated to see which dependencies have newer versions available before running uv lock --upgrade.
Speed comparison. uv is typically 10–100x faster than pip for cold installs and near-instant for cached installs. The Rust implementation eliminates Python overhead in the resolver.