uv — The Unified Python Toolchain
Parent: Python Patterns and Best Practices · researched 2026-06-01T04:44:00.144Z· 11 sources · 9 concepts · skill uv-python-toolchain
uv is an extremely fast Python package and project manager written in Rust by
uv — The Unified Python Toolchain
- uv is an extremely fast Python package and project manager written in Rust by [source]
- Astral (the Ruff team). It is a single static binary that consolidates the jobs [source]
- previously spread across pip, pip-tools, virtualenv/venv, pyenv, [source]
- pipx, poetry, twine, and build - typically 10-100x faster than the [source]
- pip/pip-tools baseline. This reference covers the five pillars named in the [source]
- brief: project/workspace management, the universal lockfile, [source]
- Python-version install/pinning, the tool/pipx replacement, and the [source]
- pip-compatible interface - plus the build backend, PEP 723 scripts, and [source]
- configuration/caching. [source]
- > For everyday Python idioms, async, typing, and a uv quick-start cheat sheet, [source]
- > see references/python-patterns.md. For static type checkers (mypy/Pyright/ [source]
- > ty/Pyrefly) see references/python-static-type-checking.md; for pytest/ [source]
- > Hypothesis see references/python-testing.md. This file is the deep, [source]
- > tool-specific reference for uv itself. Defer to the official docs [source]
- > (https://docs.astral.sh/uv/) as the source of truth for exact flags/versions. [source]
Command surface at a glance
- uv <command> top-level commands (uv 0.11.x): [source]
- Two front-doors that confuse newcomers: the project interface (uv add, [source]
- uv sync, uv run - operates on pyproject.toml + uv.lock, the recommended [source]
- path) and the pip interface (uv pip ... - a drop-in low-level imperative [source]
- layer with no lockfile). Don't mix them on the same environment expecting [source]
- managed state; the project interface owns uv.lock, the pip interface does not. [source]
Single project
- uv run and uv sync auto-create the .venv, auto-install the pinned [source]
- Python if missing, auto-lock, and auto-sync before running - so the venv [source]
- is an implementation detail you rarely activate manually. Key files: [source]
- pyproject.toml - standard PEP 621 metadata + [tool.uv] config, [dependency-groups], [tool.uv.sources]. [source]
- uv.lock - the universal lockfile (commit to git; never hand-edit). [source]
- .python-version - the pinned interpreter (written by uv python pin). [source]
- .venv/ - the project virtualenv (gitignored). [source]
- Dependency groups (PEP 735, the modern replacement for [project.optional-dependencies] [source]
- "extras" used as dev deps): dev is the implicit default group. Control install [source]
- scope on sync/run: --group <g>, --only-group <g>, --no-dev, --no-default-groups, [source]
- --all-groups. Extras (consumer-facing optional features) are separate: [source]
- --extra <e>, --all-extras. [source]
- Dependency sources - [tool.uv.sources] redirects a dependency away from PyPI: [source]
- [tool.uv.sources] is non-standard metadata that uv strips when building a [source]
- distribution - it affects your dev resolution, not what downstream consumers get. [source]
Workspaces (monorepo)
- A workspace is multiple packages in one repo sharing one uv.lock and one [source]
- .venv, each with its own pyproject.toml. Inspired by Cargo workspaces. [source]
- Members are addressed with uv run --package <member> / uv add --package <member> <dep>. [source]
- workspace = true sources are treated as editable - cross-package edits are live. [source]
- Root [tool.uv.sources] apply to all members unless a member overrides them. [source]
- Use a workspace when packages are co-released and tightly coupled; use [source]
- separate projects (path/git sources) when versions must diverge or a member [source]
- needs a conflicting dependency (a single shared lock forbids conflicts). [source]
2. The universal lockfile (`uv.lock`)
- uv.lock is a universal (cross-platform) resolution: one lockfile valid for [source]
- every OS, architecture, and Python version inside the project's requires-python [source]
- range. A package can appear multiple times with different versions/URLs gated by [source]
- environment markers (sys_platform, python_full_version, etc.); the marker [source]
- chooses which entry installs on a given machine. [source]
- Resolution knobs (also valid in the pip interface): [source]
- --resolution {highest|lowest|lowest-direct} (env UV_RESOLUTION). lowest [source]
- is for testing your declared lower bounds; lowest-direct lowers your direct [source]
- deps but keeps transitive at highest. [source]
- --prerelease {disallow|allow|if-necessary|explicit|if-necessary-or-explicit}. [source]
- --fork-strategy {requires-python|fewest} - requires-python (default) picks [source]
- the latest version compatible with each supported Python minor; fewest [source]
- minimizes the number of distinct versions. [source]
- requires-python semantics: uv considers only lower bounds of dependency [source]
- requires-python and ignores upper bounds (>=3.8,<4 is treated as >=3.8), [source]
- because honoring upper bounds causes pathological backtracking. Your project's [source]
- requires-python must be a subset of every dependency's range. [source]
- Export / interop - uv.lock is uv-native; export to standard formats for [source]
- uv reads pylock.toml (PEP 751) for install but keeps uv.lock as its [source]
- native format because PEP 751 doesn't yet capture everything uv needs (e.g. full [source]
- fork/marker model). Treat uv.lock as the source of truth and pylock.toml/ [source]
- requirements.txt as generated artifacts. [source]
- uv.lock is deterministic and committed. The cross-platform guarantee is [source]
- the headline benefit over a platform-specific pip-compile requirements.txt. [source]
3. Python version install & pinning
- uv downloads and manages standalone CPython/PyPy builds (python-build-standalone) [source]
- — no pyenv needed, and no system Python required. [source]
- Selection & preference: [source]
- Request syntax: 3.12, [email protected], [email protected], >=3.11,<3.13, or a path. [source]
- .python-version (project) / .python-versions pins the interpreter; requires-python [source]
- in pyproject.toml bounds what is acceptable. [source]
- --python-preference {only-managed|managed|system|only-system} (`[tool.uv] [source]
- python-preference) controls managed-vs-system priority. managed` (default) [source]
- prefers uv's downloads but will use a compatible system Python. [source]
- --no-python-downloads (env UV_PYTHON_DOWNLOADS=never) forbids auto-download [source]
- — useful in locked-down CI/containers. [source]
- Automatic downloads: uvx [email protected] -c ... or uv venv will fetch a missing [source]
- interpreter on demand unless downloads are disabled. [source]
4. Tool / pipx replacement (`uv tool`, `uvx`)
- uv runs and installs CLI tools from Python packages in isolated environments, [source]
- uvx = uv tool run: an ephemeral environment, ideal for one-off or [source]
- CI invocations; it caches the env so repeat runs are fast. [source]
- uv tool install is persistent: executables are symlinked (copied on [source]
- Windows) into the tool bin dir. Only the package's own entry points are [source]
- exposed - not its dependencies' executables. [source]
- If the bin dir isn't on PATH, uv warns; run uv tool update-shell. [source]
5. pip-compatible interface (`uv pip`)
- A near-drop-in, much faster reimplementation of the pip / pip-tools workflow. [source]
- Operates imperatively on an environment with **no lockfile and no automatic [source]
- project management** - use it for legacy flows, scripts, containers, or when you [source]
- explicitly want pip semantics. [source]
- Deliberate differences from pip (uv is stricter / more correct by default): [source]
- uv pip install does not mutate a global Python unless you pass --system [source]
- or activate a venv; otherwise it targets .venv. [source]
- uv pip compile --universal produces one marker-annotated requirements.txt [source]
- valid across platforms - the pip-tools world's per-platform lock pain solved. [source]
- uv pip sync is destructive-to-match (like pip-sync): it uninstalls anything [source]
- not in the file. Use it for reproducible CI/containers. [source]
- Resolution flags (--resolution, --prerelease, --index, --index-strategy) [source]
- match the project interface. [source]
Build backend, publishing & PEP 723 scripts
- Build backend. Since mid-2025 uv init --package/--lib default to uv's own [source]
- PEP 517 backend uv_build (package uv-build), zero-config for pure-Python [source]
- projects; Hatchling remains a fine alternative for projects needing plugins or [source]
- PEP 723 inline-script metadata - single-file scripts declare their own deps [source]
- and Python, run in an isolated ephemeral env: [source]
Configuration & cache
- Config files: [tool.uv] in pyproject.toml (project), or a standalone [source]
- uv.toml (project or ~/.config/uv/uv.toml global). uv.toml wins over [source]
- [tool.uv] when both exist. [source]
- Env vars: almost every flag has one - UV_RESOLUTION, UV_PRERELEASE, [source]
- UV_PYTHON, UV_PYTHON_DOWNLOADS, UV_INDEX/UV_DEFAULT_INDEX, [source]
- UV_CACHE_DIR, UV_NO_CACHE, UV_PROJECT_ENVIRONMENT, UV_SYSTEM_PYTHON. [source]
- Indexes: [[tool.uv.index]] (name + url, optional default/explicit), [source]
- --index/--default-index, --index-strategy {first-index|unsafe-first-match|unsafe-best-match}. [source]
- Cache: global content-addressed store with hardlinks into venvs (why uv is [source]
- fast and disk-light). uv cache dir / uv cache clean / uv cache prune [source]
- (--ci prunes safely for caching layers). --no-cache / UV_NO_CACHE for [source]
Practical patterns
- Adopt incrementally: start with uv pip install -r requirements.txt / [source]
- uv venv (drop-in), then migrate to uv init + uv add + uv.lock when ready. [source]
- Reproducible CI: uv sync --locked (or uv lock --check as a gate) so a [source]
- stale lockfile fails the build instead of silently re-resolving. [source]
- Docker: copy pyproject.toml + uv.lock first, `uv sync --no-install-project [source]
- --frozen for a cacheable deps layer, then copy source and uv sync --frozen`. [source]
- Use the ghcr.io/astral-sh/uv image or COPY --from=ghcr.io/astral-sh/uv /uv /uv. [source]
- Set UV_COMPILE_BYTECODE=1, UV_LINK_MODE=copy in containers. [source]
- GitHub Actions: astral-sh/setup-uv@v5 installs uv and caches automatically; [source]
- combine with uv python install. [source]
- Monorepo: one workspace + one uv.lock; per-service deploys via [source]
- uv sync --package <svc> or uv export --package <svc>. [source]
- Pin Python per project: uv python pin 3.12 so contributors and CI agree. [source]
Anti-patterns
- Mixing interfaces on one env expecting managed state - uv pip install [source]
- into a project .venv then uv sync will reconcile to the lock and remove [source]
- your manual installs. Pick the project interface or the pip interface. [source]
- Hand-editing uv.lock - it's generated; edit pyproject.toml and re-lock. [source]
- Committing requirements.txt as the source of truth in a uv project - the [source]
- lock is uv.lock; export requirements.txt as a derived artifact. [source]
- Putting dev tools in [project.dependencies] - use [dependency-groups] [source]
- (uv add --dev) so they don't ship to consumers. [source]
- A workspace with conflicting dependency versions across members - a single [source]
- shared lock can't satisfy a true conflict; split into separate projects with [source]
- path/git sources instead. [source]
- uv pip install without --system inside a container and then wondering [source]
- why the system interpreter is empty - in containers you usually want --system [source]
- or an explicitly created venv on PATH. [source]
- Forgetting requires-python is a subset constraint - if your floor is [source]
- >=3.8 but a dependency dropped 3.8, universal resolution fails; raise your [source]
- floor or constrain the dep. [source]
Troubleshooting
- "No interpreter found for Python 3.x" → uv python install 3.x, or you set [source]
- --no-python-downloads/UV_PYTHON_DOWNLOADS=never in a locked env. [source]
- Lockfile out of date in CI (uv sync --locked fails) → run uv lock [source]
- locally and commit; something changed pyproject.toml without re-locking. [source]
- "Tool executable not on PATH" after uv tool install → uv tool update-shell [source]
- then restart the shell; verify with uv tool dir --bin. [source]
- Resolution is "too constrained"/conflict → check overlapping requires-python, [source]
- try --resolution lowest-direct to isolate, or uv tree --invert <pkg> to see [source]
- Editable workspace dep not picking up changes → confirm the member is in [source]
- [tool.uv.workspace] members and referenced with { workspace = true } in [source]
- [tool.uv.sources]; re-run uv sync. [source]
- Private index auth → uv auth or UV_INDEX_<NAME>_USERNAME/PASSWORD; set [source]
- --index-strategy if a package exists on multiple indexes. [source]
References
- uv official docs - https://docs.astral.sh/uv/ (projects, workspaces, resolution, tools, python-versions, pip, build-backend, export, settings) [source]
- uv resolution & universal lockfile - https://docs.astral.sh/uv/concepts/resolution/ [source]
- uv workspaces - https://docs.astral.sh/uv/concepts/projects/workspaces/ [source]
- uv tools (pipx replacement) - https://docs.astral.sh/uv/concepts/tools/ and /guides/tools/ [source]
- uv Python versions - https://docs.astral.sh/uv/concepts/python-versions/ and /guides/install-python/ [source]
- uv pip interface - https://docs.astral.sh/uv/pip/ [source]
- uv build backend (stable, default since 2025) - https://docs.astral.sh/uv/concepts/build-backend/ [source]
- PEP 751 pylock.toml - https://packaging.python.org/en/latest/specifications/pylock-toml/ [source]
- Real Python: Managing Python projects with uv - https://realpython.com/python-uv/ [source]
- pydevtools: uv complete guide / build-backend-now-stable / uv 0.8 PATH - https://pydevtools.com/handbook/explanation/uv-complete-guide/ [source]
- Verified locally against uv 0.11.16 (Homebrew, 2026-05) - command surface, uv init output, export formats, lock/sync flags [source]
Children
- Project & workspace management (uv init/add/remove/sync/run/lock/tree, [dependency-groups] PEP 735, [tool.uv.sources], multi-package workspaces with shared uv.lock) (frontier)
- Universal lockfile (uv.lock cross-platform marker resolution, --resolution highest/lowest/lowest-direct, --prerelease, --fork-strategy, --locked/--frozen/--check, requires-python subset rule) (frontier)
- Lockfile export & interop (uv export to requirements.txt / pylock.toml PEP 751 / CycloneDX SBOM) (frontier)
- Python version install & pinning (uv python install/pin/list/find, .python-version, python-preference managed vs system, UV_PYTHON_DOWNLOADS) (frontier)
- Tool / pipx replacement (uvx / uv tool run ephemeral, uv tool install/upgrade/list/update-shell) (frontier)
- pip-compatible interface (uv pip install/compile --universal/sync, uv venv, --system) (frontier)
- Build backend & publishing (uv_build default since 2025, uv build, uv publish) (frontier)
- PEP 723 inline-script metadata (uv run script.py, uv add --script, --with) (frontier)
- Configuration & cache ([tool.uv]/uv.toml, UV_* env vars, [[tool.uv.index]], content-addressed cache) (frontier)
Frontier under this node: Build backend & publishing (uv_build default since 2025, uv build, uv publish), Configuration & cache ([tool.uv]/uv.toml, UV_* env vars, [[tool.uv.index]], content-addressed cache), Lockfile export & interop (uv export to requirements.txt / pylock.toml PEP 751 / CycloneDX SBOM), PEP 723 inline-script metadata (uv run script.py, uv add --script, --with), Project & workspace management (uv init/add/remove/sync/run/lock/tree, [dependency-groups] PEP 735, [tool.uv.sources], multi-package workspaces with shared uv.lock), Python version install & pinning (uv python install/pin/list/find, .python-version, python-preference managed vs system, UV_PYTHON_DOWNLOADS), Tool / pipx replacement (uvx / uv tool run ephemeral, uv tool install/upgrade/list/update-shell), Universal lockfile (uv.lock cross-platform marker resolution, --resolution highest/lowest/lowest-direct, --prerelease, --fork-strategy, --locked/--frozen/--check, requires-python subset rule), pip-compatible interface (uv pip install/compile --universal/sync, uv venv, --system)