Python uv: The Fast Package Manager Guide
uv is an ultra-fast Python package and project manager written in Rust, built by Astral (the team behind ruff). It is a single tool that replaces pip, pip-tools, pipx, poetry, pyenv, and virtualenv. Dependency resolution that takes pip 30 seconds often completes in under 1 second with uv.
1. Why uv?
The Python packaging ecosystem has long been a patchwork of tools: pip for installing, venv for environments, pip-tools for lockfiles, pyenv for Python versions, pipx for CLI tools. Each has its own configuration, quirks, and failure modes. uv unifies all of these into a single, fast binary.
- 10-100x faster — Written in Rust with parallel dependency resolution and a global package cache. Cold installs that take pip minutes finish in seconds.
- Drop-in pip replacement —
uv pip installworks as a direct substitute with the same CLI flags. - Project management —
uv init,uv add,uv sync, anduv lockgive you a complete project workflow like Poetry or PDM. - Python version management —
uv python install 3.12downloads and manages Python interpreters, replacing pyenv. - Tool runner —
uv tool installanduvxreplace pipx for installing CLI tools in isolated environments. - Single static binary — No Python required to install uv itself. Works on Linux, macOS, and Windows.
- Standards-based — Uses PEP 621
pyproject.toml, PEP 508 dependency specifiers, and standard virtual environments.
2. Installation
Standalone installer (recommended)
# Linux / macOS / WSL
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.sh | iex"
# Verify
uv --version
# uv 0.6.x
The installer places the binary in ~/.local/bin (Linux/macOS) or %USERPROFILE%\.local\bin (Windows). It adds this to your PATH automatically.
Other installation methods
# Via pip / Homebrew / conda
pip install uv
brew install uv
conda install -c conda-forge uv
# Pin a specific version
curl -LsSf https://astral.sh/uv/0.6.0/install.sh | sh
# Self-update
uv self update
Shell completions
uv generate-shell-completion bash > ~/.local/share/bash-completion/completions/uv
uv generate-shell-completion zsh > ~/.zfunc/_uv
uv generate-shell-completion fish > ~/.config/fish/completions/uv.fish
3. Project Setup with uv init
Creating a new project
# Create a new application project
uv init my-app
cd my-app
# Creates:
# my-app/
# .python-version # e.g., 3.12
# pyproject.toml # PEP 621 project metadata
# README.md
# hello.py # sample entry point
# Create a library project (for publishing to PyPI)
uv init --lib my-library
# Creates src/my_library/__init__.py with proper package structure
# Create a packaged application (with src layout)
uv init --package my-service
Initializing in an existing directory
# In an existing project directory
cd existing-project
uv init
# uv detects existing pyproject.toml and works with it
# If you have a Poetry/PDM project, uv reads their formats too
The generated pyproject.toml
[project]
name = "my-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
This is standard PEP 621 format — no [tool.poetry] or proprietary sections. Any PEP-compliant tool can read it.
4. Dependency Management
Adding dependencies
# Add a runtime dependency
uv add requests
# Add with version constraint
uv add "django>=4.2,<5.0"
# Add multiple at once
uv add flask sqlalchemy alembic
# Add with extras
uv add "fastapi[standard]"
# Add from git
uv add git+https://github.com/encode/httpx
# Add from a git tag or branch
uv add git+https://github.com/encode/httpx@0.27.0
uv add git+https://github.com/encode/httpx@main
# Add a local path dependency (editable)
uv add --editable ../shared-lib
# Add from requirements.txt
uv add -r requirements.txt
Each uv add updates pyproject.toml, resolves the full dependency tree, writes uv.lock, and syncs the virtual environment — all in one step.
Adding dev dependencies
# Add to the dev dependency group
uv add --dev pytest ruff mypy
# Add to a custom group
uv add --group docs sphinx sphinx-rtd-theme
uv add --group test pytest-cov factory-boy
Dev and group dependencies appear in pyproject.toml under [dependency-groups]:
[dependency-groups]
dev = ["pytest>=8.0", "ruff>=0.9", "mypy>=1.14"]
docs = ["sphinx>=7.2", "sphinx-rtd-theme>=2.0"]
test = ["pytest-cov>=6.0", "factory-boy>=3.3"]
Removing dependencies
uv remove requests
uv remove --dev pytest
uv remove --group docs sphinx
Updating dependencies
# Update a single package to its latest allowed version
uv lock --upgrade-package requests
uv sync
# Update all packages
uv lock --upgrade
uv sync
# See what's currently installed
uv pip list
5. The Lock File: uv.lock
uv produces a cross-platform lock file that pins every dependency (including transitive ones) with exact versions and hashes. Unlike poetry.lock, uv.lock is a human-readable TOML file that locks for all platforms simultaneously.
# Generate or update the lock file (without installing)
uv lock
# Install exactly what's in the lock file
uv sync
# Install without dev dependencies (production)
uv sync --no-dev
# Install only specific groups
uv sync --group docs
# Verify lock file is up-to-date with pyproject.toml
uv lock --check
Always commit uv.lock to version control. This ensures every developer and CI server installs the exact same dependency versions.
6. Running Code with uv run
uv run executes a command in the project's virtual environment. It automatically creates the environment and installs dependencies if needed.
# Run a Python script
uv run python app.py
# Run pytest
uv run pytest
# Run any installed CLI tool
uv run ruff check .
uv run mypy src/
# Pass arguments
uv run python -m flask run --port 8080
# Run with an inline dependency (no pyproject.toml needed)
uv run --with requests python -c "import requests; print(requests.get('https://httpbin.org/ip').json())"
Inline script dependencies
uv supports PEP 723 inline script metadata. Add dependency declarations directly in a Python file:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "requests>=2.31",
# "rich>=13.0",
# ]
# ///
import requests
from rich import print
resp = requests.get("https://api.github.com/zen")
print(f"[bold green]{resp.text}[/bold green]")
# uv reads the metadata and installs deps automatically
uv run fetch_zen.py
This is incredibly powerful for standalone scripts — no pyproject.toml, no requirements.txt, no virtual environment setup. Just run it.
7. Managing Python Versions
uv can download and manage Python installations, replacing pyenv entirely.
# Install a specific Python version
uv python install 3.12
uv python install 3.11 3.13
# Install the latest available
uv python install
# List installed versions
uv python list
# Pin a version for the current project
uv python pin 3.12
# This creates a .python-version file
# uv reads it automatically for uv run, uv sync, etc.
# Find where a specific version is installed
uv python find 3.12
# Uninstall a version
uv python uninstall 3.11
When you run uv sync or uv run, uv automatically downloads the required Python version if it is not already available. The requires-python field in pyproject.toml determines compatible versions.
8. Virtual Environments
uv creates and manages virtual environments automatically when you use project commands (uv sync, uv run). You can also manage them manually.
# Create a virtual environment (default: .venv in current dir)
uv venv
# Create with a specific Python version
uv venv --python 3.12
# Create in a custom location
uv venv /path/to/my-env
# Create with a specific name
uv venv .venv-test
# Activate it (standard activation, same as any venv)
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
In practice, you rarely need to create or activate environments manually. uv run handles it automatically. The environment lives at .venv/ in your project root.
9. Pip Compatibility Mode
uv provides a full pip-compatible interface for existing workflows and scripts that expect pip commands.
# Direct pip replacements — same flags, 10-100x faster
uv pip install requests
uv pip install -r requirements.txt
uv pip install -e ".[dev]"
uv pip uninstall requests
uv pip freeze > requirements.txt
uv pip list
uv pip show requests
# Compile a requirements.txt lock file (replaces pip-tools)
uv pip compile requirements.in -o requirements.txt
uv pip compile pyproject.toml -o requirements.txt
# Sync environment to match requirements exactly
uv pip sync requirements.txt
uv pip compile replaces pip-compile from pip-tools. It takes loose requirements and produces a fully pinned requirements.txt with hashes.
10. Installing CLI Tools with uv tool
uv tool replaces pipx — it installs Python CLI tools in isolated environments so they do not pollute your system packages.
# Install a CLI tool globally
uv tool install ruff
uv tool install black
uv tool install httpie
# Run a tool without installing it (like npx)
uvx ruff check .
uvx black --check .
uvx cowsay "hello from uv"
# Run a specific version
uvx ruff@0.9.0 check .
# List installed tools
uv tool list
# Upgrade a tool
uv tool upgrade ruff
uv tool upgrade --all
# Uninstall
uv tool uninstall ruff
uvx is shorthand for uv tool run. It downloads the tool into a temporary, cached environment and runs it immediately. Perfect for one-off tasks.
11. pyproject.toml Configuration
A full pyproject.toml for a uv-managed project:
[project]
name = "my-service"
version = "1.2.0"
description = "A web service built with FastAPI"
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.11"
authors = [{ name = "Jane Doe", email = "jane@example.com" }]
keywords = ["api", "web", "fastapi"]
dependencies = [
"fastapi[standard]>=0.115",
"sqlalchemy>=2.0",
"alembic>=1.14",
"pydantic-settings>=2.0",
]
[project.scripts]
my-service = "my_service.cli:main"
[project.urls]
Repository = "https://github.com/jane/my-service"
[dependency-groups]
dev = ["pytest>=8.0", "ruff>=0.9", "mypy>=1.14"]
docs = ["sphinx>=7.2", "sphinx-rtd-theme>=2.0"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.pytest.ini_options]
testpaths = ["tests"]
The [tool.uv] section supports additional configuration like custom indexes (index = [...]), dependency overrides (override-dependencies), and Python version constraints (python-version = "3.12").
12. Workspaces for Monorepos
uv workspaces let you manage multiple packages in a single repository with a shared lock file and virtual environment.
# Project structure
monorepo/
pyproject.toml # root workspace config
uv.lock # shared lock file
packages/
core/
pyproject.toml
src/core/...
api/
pyproject.toml
src/api/...
worker/
pyproject.toml
src/worker/...
Root pyproject.toml
[project]
name = "monorepo"
version = "0.0.0"
requires-python = ">=3.12"
[tool.uv.workspace]
members = ["packages/*"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Member pyproject.toml (packages/api)
[project]
name = "api"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"core", # references the workspace member
"fastapi>=0.115",
]
[tool.uv.sources]
core = { workspace = true }
Working with workspaces
# Sync the entire workspace
uv sync
# Run a command in a specific package
uv run --package api python -m api.main
# Add a dependency to a specific package
uv add --package worker celery
# Lock the entire workspace
uv lock
13. Migration Guides
From pip + requirements.txt
# Step 1: Initialize a uv project
uv init
# Step 2: Add your existing dependencies
uv add -r requirements.txt
# Step 3: Add dev dependencies
uv add --dev -r requirements-dev.txt
# Step 4: Verify everything installs
uv sync
# Step 5: Run your tests
uv run pytest
# You can now delete requirements.txt and use uv.lock instead
# Or keep generating it: uv pip compile pyproject.toml -o requirements.txt
From Poetry
# uv reads pyproject.toml with [tool.poetry] sections
# Step 1: Generate a uv lock file
uv lock
# Step 2: Sync the environment
uv sync
# Step 3: Verify your project works
uv run pytest
# Step 4: Migrate pyproject.toml to PEP 621 format
# Move [tool.poetry.dependencies] to [project.dependencies]
# Move [tool.poetry.group.dev.dependencies] to [dependency-groups]
# Update [build-system] from poetry-core to hatchling
# Step 5: Remove Poetry artifacts
# Delete poetry.lock (replaced by uv.lock)
# Remove [tool.poetry] sections from pyproject.toml
From pipenv
# Step 1: Export to requirements.txt
pipenv requirements > requirements.txt
pipenv requirements --dev > requirements-dev.txt
# Step 2: Initialize uv project
uv init
# Step 3: Import dependencies
uv add -r requirements.txt
uv add --dev -r requirements-dev.txt
# Step 4: Verify and clean up
uv sync
uv run pytest
# Delete Pipfile, Pipfile.lock
14. CI/CD Integration
GitHub Actions
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --frozen
- name: Run tests
run: uv run pytest --cov=src/
- name: Lint
run: uv run ruff check .
--frozen tells uv to use the existing uv.lock without modifying it. This catches cases where someone forgot to update the lock file.
GitLab CI
# .gitlab-ci.yml
image: python:3.12-slim
variables:
UV_CACHE_DIR: "$CI_PROJECT_DIR/.uv-cache"
cache:
paths:
- .uv-cache/
- .venv/
before_script:
- pip install uv
- uv sync --frozen
test:
script:
- uv run pytest
lint:
script:
- uv run ruff check .
15. Docker Integration
Multi-stage build (recommended)
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app
# Enable bytecode compilation for faster startup
ENV UV_COMPILE_BYTECODE=1
# Use the system Python (no venv in container)
ENV UV_LINK_MODE=copy
# Install dependencies first (layer caching)
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
# Copy source and install the project itself
COPY . .
RUN uv sync --frozen --no-dev
# --- Runtime stage ---
FROM python:3.12-slim-bookworm
WORKDIR /app
COPY --from=builder /app/.venv .venv
COPY --from=builder /app/src src
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "my_service"]
Simple single-stage build
FROM python:3.12-slim
# Copy uv binary from official image
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
COPY . .
RUN uv sync --frozen --no-dev
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "my_service"]
16. Performance Benchmarks
Real-world install times for a typical web project (~40 dependencies):
| Scenario | pip | poetry | uv |
|---|---|---|---|
| Cold install (no cache) | 32s | 45s | 2.1s |
| Warm install (cached) | 8s | 12s | 0.4s |
| Resolve only (lock) | N/A | 18s | 0.8s |
| Add single package | 5s | 15s | 0.5s |
| Create venv | 3s | 4s | 0.1s |
uv achieves this speed through several techniques: parallel downloads and extraction, a global content-addressable cache, hard-linking packages from the cache into virtual environments, and efficient Rust-native dependency resolution.
17. uv vs pip vs Poetry vs PDM
| Feature | pip + venv | Poetry | PDM | uv |
|---|---|---|---|---|
| Speed | Slow | Moderate | Moderate | Very fast |
| Lock file | Manual (freeze) | poetry.lock | pdm.lock | uv.lock |
| Dependency resolver | Basic | SAT solver | Good | Fast SAT solver |
| Python management | No | No | No | Built-in |
| Venv management | Manual | Automatic | Automatic | Automatic |
| CLI tool install | No | No | No | uv tool (pipx) |
| Build & publish | Needs twine | Built-in | Built-in | uv build / publish |
| PEP 621 | N/A | Since v2.0 | Yes | Yes |
| Workspaces | No | Path deps | No | Native |
| Inline scripts | No | No | No | PEP 723 |
| Cross-platform lock | No | No | Yes | Yes |
| Written in | Python | Python | Python | Rust |
Bottom line: For new projects in 2026, uv is the default recommendation. It is faster, handles more tasks, and follows standards. Use Poetry if your team already has a large Poetry codebase. Use pip for simple, one-off scripts.
18. Tips and Best Practices
Project structure and .gitignore
# Recommended layout
my-app/
pyproject.toml
uv.lock # Always commit this
.python-version
src/my_app/
__init__.py
main.py
tests/test_main.py
# .gitignore entries
.venv/
__pycache__/
*.py[cod]
Useful environment variables
UV_COMPILE_BYTECODE=1 uv sync # Compile bytecode (faster startup)
UV_NO_PROGRESS=1 uv sync # Quiet mode for CI
UV_CACHE_DIR=/tmp/uv-cache # Custom cache location
UV_INDEX_URL=https://pypi.mycompany.com/simple/ # Private index
Building and publishing packages
# Build sdist and wheel
uv build
# Publish to PyPI (set UV_PUBLISH_TOKEN env var)
uv publish
# Publish to TestPyPI
uv publish --index-url https://test.pypi.org/legacy/
Quick Reference Cheat Sheet
| Task | Command |
|---|---|
| Install uv | curl -LsSf https://astral.sh/uv/install.sh | sh |
| Create new project | uv init my-app |
| Create library project | uv init --lib my-lib |
| Add dependency | uv add requests |
| Add dev dependency | uv add --dev pytest |
| Remove dependency | uv remove requests |
| Sync from lock file | uv sync |
| Production sync | uv sync --no-dev |
| Update lock file | uv lock --upgrade |
| Run a command | uv run pytest |
| Run inline script | uv run script.py |
| Install Python | uv python install 3.12 |
| Pin Python version | uv python pin 3.12 |
| Create venv | uv venv |
| Install CLI tool | uv tool install ruff |
| Run tool once | uvx ruff check . |
| pip compatibility | uv pip install -r requirements.txt |
| Compile requirements | uv pip compile requirements.in |
| Build package | uv build |
| Publish to PyPI | uv publish |
| Self-update | uv self update |
Frequently Asked Questions
What is uv and why is it faster than pip?
uv is a Python package manager written in Rust by Astral (the ruff team). It is 10-100x faster than pip because it resolves dependencies in parallel, uses a global cache to avoid redundant downloads, and leverages Rust's performance for all I/O and computation. It replaces pip, pip-tools, pipx, poetry, pyenv, and virtualenv in a single binary.
How do I migrate from pip to uv?
For existing projects with requirements.txt, run uv pip install -r requirements.txt as a drop-in replacement. For a full migration to uv's project system, run uv init, then uv add -r requirements.txt. uv will create a pyproject.toml and uv.lock.
How do I migrate from Poetry to uv?
uv can read Poetry's pyproject.toml format. Run uv lock in a Poetry project to generate a uv.lock file, then uv sync to install everything. Gradually migrate the [tool.poetry] sections to standard PEP 621 [project] format.
Does uv replace pyenv for managing Python versions?
Yes. uv python install 3.12 downloads and manages Python installations directly. It automatically discovers or downloads the right Python version based on your pyproject.toml requires-python field. You no longer need pyenv, deadsnakes PPA, or manual Python builds.
What is the difference between uv sync and uv pip install?
uv sync is the project-aware command: it reads pyproject.toml and uv.lock, creates a virtual environment, and installs exactly the locked dependencies. uv pip install is the pip-compatible interface for ad-hoc installs without a project structure. For repeatable builds, always use uv sync.
Can I use uv in Docker and CI/CD?
Yes. Astral provides official Docker images (ghcr.io/astral-sh/uv) and a GitHub Action (astral-sh/setup-uv). In Docker, copy the uv binary from the official image, then run uv sync --frozen for reproducible installs. In GitHub Actions, use the setup-uv action with cache enabled for fast CI builds.
Does uv support workspaces for monorepos?
Yes. Define workspace members in your root pyproject.toml under [tool.uv.workspace] with a members glob pattern. Each member has its own pyproject.toml but shares a single uv.lock and virtual environment. This is ideal for monorepos with shared libraries and multiple services.