Install

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

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Or via Homebrew
brew install uv

# Or as a Python package (bootstraps the binary)
pipx install uv

uv is a single self-contained binary — no system Python required to install it. After install:

uv --version
uv self update      # uv updates itself

Project workflow

The core commands are uv init, uv add, uv sync, uv run. They mirror what poetry/cargo do, but operate on a standard pyproject.toml with no proprietary sections.

# Create a new project
uv init my-app
cd my-app

# Add dependencies
uv add fastapi uvicorn
uv add --dev pytest ruff mypy

# Run a command inside the project's managed environment
uv run python -m my_app
uv run pytest

# Reproduce the locked environment from scratch
uv sync

uv init creates a pyproject.toml, a .python-version, a project skeleton, and a .venv when needed. uv add updates pyproject.toml AND uv.lock AND the venv in one transaction. uv run ensures the venv is up to date before executing the command — equivalent to poetry run but with no separate activate step.

Lockfiles, properly cross-platform

uv.lock records resolved versions and hashes for every supported platform (Linux x86_64, Linux aarch64, macOS, Windows) in a single file. A teammate on a different OS can uv sync the same lockfile and get a deterministic install on their platform — no separate per-platform resolution.

uv lock              # re-resolve all dependencies, write uv.lock
uv lock --upgrade    # also bump within constraints
uv lock --upgrade-package fastapi
uv tree              # show the resolved dependency tree

Python version management

uv handles Python interpreters too — pyenv is no longer needed:

uv python list                  # available versions (installed and downloadable)
uv python install 3.12 3.13     # download & cache specific versions
uv python pin 3.13              # write .python-version for this project
uv venv --python 3.11           # create a venv with a specific version

Interpreters land under ~/.local/share/uv/python/ and are reused across projects. The downloads are Astral's portable-Python builds — relocatable, statically linked enough to run without system OpenSSL, signed.

pipx replacement: uv tool

uv tool is uv's equivalent of pipx — install Python applications into isolated environments and expose their entry points on PATH:

uv tool install ruff
uv tool install black

# One-shot: run a tool without installing it
uvx ruff check .
uvx black .

uvx is shorthand for uv tool run. The first invocation downloads the tool's environment; subsequent runs are cache hits and start instantly.

Inline-metadata scripts (PEP 723)

A single-file Python script can declare its dependencies inline:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "httpx",
#   "rich",
# ]
# ///

import httpx
from rich import print

print(httpx.get("https://example.com").status_code)

uv run script.py reads the metadata block, materializes a venv with the declared dependencies (cached for reuse), and runs the script. This collapses the "tiny script that needs three packages" friction to zero — no virtualenv, no pip install, no requirements.txt.

Migrating from pip / requirements.txt

uv accepts requirements.txt directly as a compatibility surface:

uv pip install -r requirements.txt
uv pip compile pyproject.toml -o requirements.txt
uv pip sync requirements.txt    # ensure venv exactly matches requirements.txt

uv pip is uv's pip-compatible CLI — same commands and flags, just faster. For projects that don't yet have a pyproject.toml, this is the minimum-disruption path. The full project workflow (uv add/uv sync/uv.lock) is the long-term destination.

Migrating from poetry

Most poetry projects already have a usable pyproject.toml. Two changes:

  1. Move the [tool.poetry] section to the standard [project] table (PEP 621). Dependencies move from [tool.poetry.dependencies] to [project] dependencies = [...].
  2. Delete poetry.lock, run uv lock to generate uv.lock.

uv keeps poetry-style dev groups via [dependency-groups] (PEP 735):

[dependency-groups]
dev = [
    "pytest>=8",
    "ruff",
    "mypy",
]
uv add --group dev pytest
uv sync --group dev        # install runtime + dev
uv sync                    # install runtime only

In CI

The official GitHub Action handles caching and version pinning:

- uses: astral-sh/setup-uv@v3
  with:
    enable-cache: true
    cache-dependency-glob: "uv.lock"
- run: uv sync --frozen
- run: uv run pytest

uv sync --frozen errors if uv.lock would change — the equivalent of npm ci. Always use it in CI; never use plain uv sync there (which would silently re-resolve).

What it doesn't (yet) replace

Build backends: uv invokes the project's build backend (hatchling, setuptools, flit, maturin) for building wheels; it isn't a build backend itself. Pick a separate one in [build-system]. Hatchling is a reasonable default for pure-Python packages; maturin if there's a Rust extension.

For most everyday workflow — install, lock, run, manage Python versions, run dev tools, ship to CI — uv covers it. Once a project is on uv, the local toolchain is a single binary instead of pip + pipx + pyenv + poetry + virtualenv, and that single binary is dramatically faster than the sum of those.