uv (Astral) cheatsheet — Python’s fastest packaging tool in 2026.
Install
curl -LsSf https://astral.sh/uv/install.sh | sh
# or
brew install uv
Create project
uv init myapp
cd myapp
Creates pyproject.toml, .python-version, src/myapp/.
Add deps
uv add fastapi pydantic sqlalchemy[asyncio]
uv add --dev pytest pytest-anyio httpx ruff mypy
uv add 'pydantic>=2.5,<3'
uv add 'requests; python_version < "3.13"'
uv add -e ../my-other-package # editable
uv add git+https://github.com/x/y.git
Remove deps
uv remove requests
Sync (install lock)
uv sync # all deps from uv.lock
uv sync --frozen # error if lock would change (CI)
uv sync --no-dev # skip dev deps
uv sync --group docs # specific group
Lock
uv lock # regenerate uv.lock
uv lock --upgrade # upgrade all
uv lock --upgrade-package pydantic
Run
uv run python main.py
uv run pytest
uv run ruff check
uv run --with httpx python script.py # one-off dep
Python version management
uv python list
uv python install 3.13
uv python pin 3.13 # writes .python-version
uv python find
Tool install (replace pipx)
uv tool install ruff
uv tool install black
uv tool install ipython
uv tool list
uv tool upgrade --all
uv tool run pytest # without installing
Or shorter:
uvx pytest # tool run
uvx --with httpx python -c "import httpx; print(httpx.__version__)"
pyproject.toml structure
[project]
name = "myapp"
version = "0.1.0"
description = "..."
authors = [{name = "Me"}]
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"fastapi>=0.115",
"pydantic>=2.9",
]
[dependency-groups]
dev = ["pytest", "ruff"]
docs = ["mkdocs", "mkdocs-material"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
package = true # treats project as installable
Workspaces (monorepo)
[tool.uv.workspace]
members = ["packages/*", "apps/*"]
Each package has its own pyproject; uv links them.
Sources (override registry per dep)
[tool.uv.sources]
mypackage = { git = "https://github.com/me/mypackage", rev = "main" }
local-pkg = { path = "../local-pkg" }
Build a wheel
uv build # creates dist/*.whl + *.tar.gz
uv build --sdist
uv build --wheel
Publish
uv publish # to PyPI
uv publish --index test-pypi
Cache
uv cache dir
uv cache clean
uv cache prune --ci # CI-friendly prune
Pip-compatible interface
uv pip install requests # like pip install
uv pip list
uv pip freeze
uv pip uninstall requests
For legacy workflows; project workflow (uv add) is preferred.
.python-version
3.13
uv auto-detects and uses this. Per-project Python version.
Inline script deps (PEP 723)
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.13"
# dependencies = ["httpx", "rich"]
# ///
import httpx
from rich import print
print(httpx.get("https://example.com").status_code)
Run:
uv run script.py
Self-contained scripts; uv installs deps on demand.
CI
- uses: astral-sh/setup-uv@v3
- run: uv sync --frozen
- run: uv run pytest
Cache-friendly:
- uses: astral-sh/setup-uv@v3
with:
enable-cache: true
Common patterns
# Bootstrap new project
uv init myapp && cd myapp
uv add fastapi 'pydantic[email]>=2.5'
uv add --dev pytest pytest-anyio httpx ruff mypy
uv run uvicorn src.myapp.main:app --reload
# Run formatter / linter
uv run ruff format .
uv run ruff check . --fix
uv run mypy src
# Update one dep
uv add 'pydantic>=2.10'
uv sync
Why uv
- 10-100× faster than pip / poetry.
- One tool: venvs, lockfile, Python install, tool install, scripts.
- Drop-in compatible with
pip install ...viauv pip.
Common mistakes
- Mixing
pip installanduv syncin same env — drift. - Forgetting
--frozenin CI — non-reproducible. - Committing the venv (.venv/) — don’t.
- Not committing uv.lock — non-reproducible builds.
Read this next
If you want my uv-based project starter, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .