uv replaces pip, virtualenv, poetry, pyenv, and pipx with a single tool. By 2026 the patterns are settled. This post is the cookbook.
A new project
uv init my-app
cd my-app
uv add fastapi pydantic httpx
uv add --dev pytest ruff mypy
uv run pytest
Five commands; project ready. No virtualenv activation, no pip install, no pyenv use.
A script with inline deps (PEP 723)
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "httpx>=0.28",
# "rich>=13",
# ]
# ///
import httpx
from rich.console import Console
c = Console()
r = httpx.get("https://api.github.com/users/AlzyWelzy")
c.print(r.json())
chmod +x script.py
./script.py
uv reads the inline deps; sets up a temporary venv; runs. No project setup. PEP 723 standard; works across tools.
Lockfiles
uv lock # update lockfile from pyproject
uv sync # install exact versions from lockfile
uv sync --frozen # CI: error if lockfile is out of date
Lockfile (uv.lock) is committed. Reproducible installs across machines.
Workspaces
# pyproject.toml at root
[tool.uv.workspace]
members = ["api", "core", "cli"]
[tool.uv.sources]
core = { workspace = true }
api = { workspace = true }
# api/pyproject.toml
[project]
name = "api"
dependencies = ["core", "fastapi"]
[tool.uv.sources]
core = { workspace = true }
uv sync at root resolves the whole workspace. Each package can be installed independently for tests / build.
Python version pinning
uv python install 3.13
uv python pin 3.13 # writes .python-version
Per-project Python. Replaces pyenv. The .python-version is honored automatically by uv run.
CLI tools
uv tool install ruff # globally available
uv tool install black
uvx ruff check . # one-shot run
uv tool replaces pipx. uvx runs without installing.
Docker
# syntax=docker/dockerfile:1.7
FROM python:3.13-slim AS builder
WORKDIR /app
RUN pip install --no-cache-dir uv
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
FROM python:3.13-slim
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY . .
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "app"]
Two-stage. Cache-friendly. ~150 MB final image. See Dockerfile Best Practices .
CI
- uses: astral-sh/setup-uv@v3
with: { enable-cache: true }
- run: uv python install 3.13
- run: uv sync --all-extras --frozen
- run: uv run ruff check .
- run: uv run mypy src/
- run: uv run pytest
enable-cache: true is the magic. Subsequent runs are seconds.
Editable installs
uv add --editable ./local-package
Develop a local package while it’s a dependency of the main project. Changes reflected immediately.
Optional dependencies
[project.optional-dependencies]
dev = ["pytest", "ruff", "mypy"]
ml = ["torch", "transformers"]
uv sync --extra ml
uv sync --all-extras
Group deps by use case. Don’t install ML deps in your API container.
Migrating from poetry
uvx migrate-to-uv
Reads pyproject.toml and poetry.lock; produces uv.lock. Some manual cleanup typically needed (poetry-specific config). Good enough for 80% of projects.
Migrating from requirements.txt
uv init
uv add $(cat requirements.txt | grep -v '^#')
Quick. Won’t preserve hash pins; review and add back if you had them.
Common mistakes
1. Mixing uv and pip in the same venv
uv and pip both modify .venv. Pick one per project. Mixing causes resolution conflicts.
2. uv add without commit
Adds to pyproject.toml and uv.lock. Commit both. Otherwise teammates’ uv sync fails.
3. uv pip install for new deps
uv pip install doesn’t update pyproject.toml. Use uv add instead.
4. Forgetting --frozen in CI
CI installs whatever’s resolvable. If lockfile is stale, you get drift. Always --frozen.
5. Slow CI without caching
enable-cache: true plus the actions/cache for uv’s dir. 90% time saved.
Read this next
- Modern Python Tooling 2026
- Dockerfile Best Practices
- CI/CD Best Practices in 2026
- FastAPI + Pydantic v2 + SQLAlchemy 2.0
If you want my uv project templates per use case, 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 .