uv — fast Python package/project manager, lockfiles, Python versions, uvx tool runner, Docker/CI integration. Use for Python dependency management. NOT for package publishing.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: uv description: "uv — fast Python package/project manager, lockfiles, Python versions, uvx tool runner, Docker/CI integration. Use for Python dependency management. NOT for package publishing."
uv
Ultra-fast Python package and project manager. Replaces pip, pip-tools, virtualenv, pyenv, and pipx in a single binary.
Installation
curl -LsSf https://astral.sh/uv/install.sh | sh # Standalone (recommended)
pip install uv # Or via pip/pipx/brew
Project Initialization
uv init myproject # App (no build system)
uv init --lib mylib # Library (src/ layout + build system)
uv init --package myapp # Packaged app (build system + entry point)
uv init --build-backend hatch mylib # Specify backend (hatch, flit, pdm, maturin, scikit, uv)
Dependency Management
uv add requests # Add to [project.dependencies]
uv add 'httpx>=0.27' # With version constraint
uv add --dev pytest ruff # Add to [dependency-groups] dev
uv add --group test pytest-cov # Custom dependency group
uv add --optional ml torch # Add to [project.optional-dependencies]
uv add 'jax; sys_platform == "linux"' # Platform-specific with markers
uv remove requests # Remove dependency
uv add -r requirements.txt # Import from requirements file
Dependency Sources ([tool.uv.sources])
Sources override where a dependency is fetched during development (ignored by other tools):
[tool.uv.sources]
# Git — supports branch, tag, rev, subdirectory
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }
# Local path — editable by default
mylib = { path = "./libs/mylib", editable = true }
# URL — remote wheel or sdist
special = { url = "https://example.com/special-1.0.0-py3-none-any.whl" }
# Workspace member
shared = { workspace = true }
# Pinned to a specific index
torch = { index = "pytorch" }
# CLI equivalents
uv add git+https://github.com/encode/httpx --tag 0.27.0
uv add httpx --index pytorch=https://download.pytorch.org/whl/cpu
Extras, Markers, and Constraints
[project]
dependencies = [
"transformers[torch]>=4.39", # Extras
"importlib_metadata>=7; python_version < '3.10'", # Markers
]
[project.optional-dependencies]
gpu = ["torch>=2.0", "triton"] # Install with: uv sync --extra gpu
[tool.uv]
# Force a version regardless of what dependents request
override-dependencies = ["numpy==1.26.4"]
# Narrow resolution (must be compatible with all requesters)
constraint-dependencies = ["scipy>=1.12"]
Lock and Sync
uv lock # Resolve → uv.lock (cross-platform universal)
uv lock --check # Exit 1 if lockfile would change (CI validation)
uv sync # Install from lockfile into .venv
uv sync --frozen # Install without checking/updating lockfile
uv sync --locked # Fail if lockfile is out of date
uv sync --no-dev # Skip dev dependencies
uv sync --group test --extra gpu # Include specific groups/extras
Lockfile Internals
uv.lock is a universal lockfile — human-readable TOML, committed to VCS. Key properties:
- Cross-platform: locks versions for all OS/arch/Python combos simultaneously
- Resolution forks: when different platforms need different versions, the lockfile contains multiple entries with markers (e.g., numpy 1.26 for Python 3.8, numpy 2.0 for Python 3.12+)
- Hash checking: each locked package includes hashes for integrity verification
- Not interoperable: uv.lock is uv-specific; export to
requirements.txtorpylock.tomlfor other tools
uv export --format requirements-txt # Export for pip/deployers
uv export -o pylock.toml # PEP 751 format
uv export --no-dev --frozen # Production export without re-resolving
Resolution
Strategies
[tool.uv]
resolution = "highest" # Default: latest compatible versions
# resolution = "lowest-direct" # Lowest for direct deps, highest for transitive — good for CI
# resolution = "lowest" # Lowest for everything — test against lower bounds
When to use each: highest for development. lowest-direct in CI to catch lower-bound incompatibilities in your direct deps without also downgrading transitive deps (which causes noise). lowest for thorough compatibility testing.
Universal Resolution and Platform Control
uv.lock resolves for all platforms by default. Constrain it if you only target specific ones:
[tool.uv]
# Only resolve for Linux and macOS (skip Windows)
environments = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
]
# Require wheels exist for specific platforms (fail if not)
required-environments = [
"sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
Fork Strategy and Multi-Version Resolution
When requires-python spans a wide range (e.g., >=3.8), uv will fork the resolution — selecting the latest version for newer Pythons and older versions for older Pythons. Control this with fork-strategy:
UV_FORK_STRATEGY=fewest uv lock # Minimize forks (prefer single version)
Upgrading and Pinning
uv lock --upgrade # Upgrade everything to latest
uv lock --upgrade-package httpx # Upgrade just one package
uv add 'httpx>0.1' --upgrade-package httpx # Change constraint + upgrade
Existing lockfile versions are preferred unless incompatible or --upgrade is specified.
uv run In Depth
uv run auto-syncs the project environment then runs a command. It's more than just activating a venv:
uv run pytest # Sync + run in project env
uv run --with rich python script.py # Add ephemeral dep (not saved to project)
uv run --with 'httpx==0.25' python -c "import httpx" # Override version ephemerally
uv run --no-project script.py # Skip project install entirely
uv run --isolated script.py # Fresh ephemeral env, no project context
uv run --package api-server flask run # Run in specific workspace member
uv run ensures the env is up-to-date before every invocation. Use UV_NO_SYNC=1 to skip auto-sync. Supports --env-file .env.local for env file loading.
Python Version Management
uv python install 3.12 # Download CPython 3.12
uv python install pypy@3.10 # Install PyPy
uv python list # Show available/installed
uv python pin 3.12 # Write .python-version — uv auto-downloads when needed
Virtual Environments
uv venv # Create .venv with project's Python
uv venv --python 3.11 /path/to/env # Specific version + path
uv auto-manages .venv via uv run/uv sync. Manual activation is optional. Set UV_PROJECT_ENVIRONMENT to override location.
pip Interface / Tool Management
uv pip install -r requirements.txt # Drop-in pip replacement (10-100x faster)
uv pip install -e '.[dev]' # Editable install with extras
uv pip compile requirements.in -o requirements.txt # Pin versions (like pip-tools)
uv pip compile --universal requirements.in # Cross-platform pins
uv pip sync requirements.txt # Exact install from lockfile
uvx ruff check . # Run CLI tool in ephemeral env (replaces pipx)
uv tool install ruff # Install tool persistently
Scripts with Inline Dependencies (PEP 723)
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx", "rich"]
# ///
import httpx; from rich import print; print(httpx.get("https://httpbin.org/get").json())
uv run script.py auto-installs deps in an isolated env. uv add --script script.py requests injects metadata.
Workspaces (Monorepo)
A workspace shares a single uv.lock across multiple packages:
# Root pyproject.toml
[project]
name = "monorepo"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["shared-lib"]
[tool.uv.sources]
shared-lib = { workspace = true }
[tool.uv.workspace]
members = ["packages/*"]
exclude = ["packages/experimental"]
Virtual Workspace Roots
If the root exists only to aggregate members (no code of its own), omit [project]:
# Root pyproject.toml — virtual root (no [project] table)
[tool.uv.workspace]
members = ["services/*", "libs/*"]
Workspace Behavior
- Single lockfile:
uv lockresolves all members together;uv.locklives at the root - Shared sources:
[tool.uv.sources]in root applies to all members (members can override) - Editable by default: workspace member deps are installed as editables
- Single
requires-python: the intersection of all members' ranges is enforced - Per-package commands:
uv run --package api-server flask run
When NOT to Use Workspaces
If members have conflicting requirements (e.g., one needs numpy 1.x, another needs 2.x), use independent projects with path dependencies instead — each gets its own lockfile and venv:
[tool.uv.sources]
shared = { path = "../libs/shared" } # Not workspace = true
Build System Integration
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
uv supports any PEP 517 backend: hatchling, setuptools, flit-core, pdm-backend, maturin (Rust), scikit-build-core (C++), and its own uv_build.
Build Isolation
By default, uv builds source distributions in isolated environments. Disable when needed:
uv pip install --no-build-isolation -e . # Uses current env's build deps
UV_NO_BUILD_ISOLATION=1 uv sync # Useful for editable installs with custom build deps
Build Constraints (Reproducible Builds)
# Pin build dependencies with hash checking
uv build --build-constraint constraints.txt --require-hashes
Cache System
Default location: ~/.cache/uv (Linux), ~/Library/Caches/uv (macOS). Caches registry packages (HTTP headers), git deps (commit hash), built wheels, and local directories (mtime-based).
uv cache dir # Show location
uv cache clean # Clear everything
uv cache clean numpy # Clear just one package
uv cache prune # Remove unused/old entries
uv sync --refresh # Revalidate all cached data
uv sync --refresh-package numpy # Revalidate one package
In CI, use astral-sh/setup-uv@v5 with enable-cache: true (GitHub Actions) or cache ~/.cache/uv keyed on uv.lock. For Docker, use --mount=type=cache (see Docker section). The cache is thread-safe.
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true } }] # Custom invalidation
Docker Integration
Production Multi-Stage Build
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:0.10.4 /uv /uvx /bin/
ENV UV_COMPILE_BYTECODE=1 UV_NO_INSTALLER_METADATA=1 UV_LINK_MODE=copy
WORKDIR /app
# Layer 1: deps only (cached when pyproject.toml/uv.lock unchanged)
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-dev --no-install-project --no-editable
# Layer 2: project code
COPY . .
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev --no-editable
# Runtime stage — no uv, no source code
FROM python:3.12-slim
COPY --from=builder /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
CMD ["myapp"]
System Python (Skip Venv)
Set UV_PROJECT_ENVIRONMENT=/usr/local to install directly into system Python, skipping venv creation entirely. Useful for single-app containers where a venv adds no value.
For workspace Dockerfiles, use --frozen for the deps-only layer (can't validate without all member pyproject.toml files), then --locked after full COPY. Use --no-install-workspace instead of --no-install-project.
Private Index Authentication
uv authenticates to private indexes via environment variables derived from the index name:
[[tool.uv.index]]
name = "my-registry"
url = "https://example.com/simple/"
# UV_INDEX_{NAME}_USERNAME / UV_INDEX_{NAME}_PASSWORD
# Name is uppercased, non-alphanumeric → underscore
export UV_INDEX_MY_REGISTRY_USERNAME="user"
export UV_INDEX_MY_REGISTRY_PASSWORD="token"
Also supports .netrc (~/.netrc) and keyring (UV_KEYRING_PROVIDER=subprocess). Pin internal packages to explicit indexes to prevent dependency confusion:
[tool.uv.sources]
my-internal-lib = { index = "my-registry" }
[[tool.uv.index]]
name = "my-registry"
url = "https://example.com/simple/"
explicit = true # Only pinned packages use this index
Provider Quick Reference
| Provider | Index URL | Username | Token Command |
|---|---|---|---|
| AWS CodeArtifact | https://<DOMAIN>-<ACCT>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPO>/simple/ | aws | aws codeartifact get-authorization-token --domain <D> --domain-owner <A> --query authorizationToken --output text |
| Google Artifact Registry | https://<REGION>-python.pkg.dev/<PROJECT>/<REPO>/simple/ | oauth2accesstoken | gcloud auth print-access-token |
| JFrog Artifactory | https://<ORG>.jfrog.io/artifactory/api/pypi/<REPO>/simple | <username> or "" (JWT) | API key, identity token, or access token |
| GitHub Packages | https://pypi.pkg.github.com/<OWNER>/simple/ | x-access-token | PAT with read:packages or GITHUB_TOKEN |
Docker Build-Time Auth (Secret Mounts)
Never bake credentials into layers. Use BuildKit secret mounts:
RUN --mount=type=secret,id=uv_env,target=/run/secrets/uv_env \
--mount=type=cache,target=/root/.cache/uv \
set -a && . /run/secrets/uv_env && set +a && \
uv sync --frozen --no-dev --no-install-project
# .uv-secrets (not committed): UV_INDEX_MY_REGISTRY_USERNAME=... UV_INDEX_MY_REGISTRY_PASSWORD=...
docker build --secret id=uv_env,src=.uv-secrets -t myapp .
CI Auth (GitHub Actions)
env:
UV_INDEX_MY_REGISTRY_USERNAME: ${{ secrets.INDEX_USERNAME }}
UV_INDEX_MY_REGISTRY_PASSWORD: ${{ secrets.INDEX_PASSWORD }}
steps:
- uses: astral-sh/setup-uv@v5
with:
version: "0.10.4"
enable-cache: true
- run: uv sync --locked
For OIDC (AWS, GCP), generate short-lived tokens in a step and export to $GITHUB_ENV. See private index authentication for complete provider configs, keyring setup, Docker .netrc patterns, and OIDC workflows.
CI Patterns
Lockfile Validation
uv lock --check # Exit 1 if lockfile would change
uv sync --locked # Exit 1 if lockfile is stale, then install
GitHub Actions
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
version: "0.10.4"
enable-cache: true
python-version: ${{ matrix.python-version }}
- run: uv sync --locked
- run: uv run pytest
CI Best Practices
- Pin uv version — exact version, not
latest, for reproducibility - Cache
~/.cache/uv— keyed onuv.lockchecksum - Use
--locked— fail if lockfile is stale rather than silently re-resolving - Run
uv lock --checkon PRs — catchespyproject.tomlchanges without lockfile update
Tool Integrations
pre-commit
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.10.4
hooks:
- id: uv-lock # Keep lockfile in sync with pyproject.toml
- id: uv-export # Keep requirements.txt in sync with uv.lock
tox / nox
Use tox-uv plugin (requires = tox-uv in tox.ini) or venv_backend="uv" in nox sessions for uv-powered environment creation.
Migration from pip/Poetry
From pip + requirements.txt
uv init # Creates pyproject.toml
uv add -r requirements.txt # Import all deps
uv add --dev -r requirements-dev.txt # Import dev deps
# Delete requirements.txt, commit pyproject.toml + uv.lock
From pip-tools (drop-in speedup, no restructuring)
uv pip compile requirements.in -o requirements.txt # Replaces pip-compile (10-100x faster)
uv pip sync requirements.txt # Replaces pip-sync
From Poetry
- Rewrite
[tool.poetry]→ standard[project](PEP 621) - Convert version constraints:
^1.2→>=1.2,<2,~1.2→>=1.2,<1.3 - Replace
[tool.poetry.group.dev.dependencies]→[dependency-groups] - Replace
[tool.poetry.extras]→[project.optional-dependencies] - Swap build backend from
poetry.core.masonry.apito hatchling/setuptools - Run
uv lock(poetry.lock is not importable)
From pipx
uvx ruff check . # Ephemeral run (replaces pipx run)
uv tool install ruff # Persistent install (replaces pipx install)
See full migration guide for command mappings, version constraint translation, and gotchas. See migration gotchas and environment variables for environment variable reference.
Cross-References
- docker-buildx — Use uv in Dockerfiles for fast dependency installation
- github-actions — Install Python dependencies with uv in CI workflows
- flyte-sdk — Flyte ImageSpec can use uv for faster container builds
References
- Official docs
- Configuration reference
- CLI reference
- Environment variables
- Docker guide
- GitHub Actions
- Resolution deep dive
- Cache docs
- Workspace guide
- Migration from pip
pyproject.tomlreference — annotated examples for libraries, apps, and workspaces- Migration guide — Poetry/pip/pipx command mapping, version constraint translation, and gotchas
- Advanced usage — environment variables, advanced configuration, and migration gotchas
- Troubleshooting & PyTorch/CUDA — resolution debugging, PyTorch index patterns, common errors
- Private index authentication — AWS CodeArtifact, JFrog, Google AR, GitHub Packages, Docker/CI auth patterns
More by tylertitsworth
View allTensorRT-LLM — engine building, quantization (FP8/FP4/INT4/AWQ), Python LLM API, AutoDeploy, KV cache tuning, in-flight batching, disaggregated serving with HTTP cluster management, Ray orchestrator, sparse attention (RocketKV), Triton backend. Use when optimizing directly with TRT-LLM. NOT for NIM deployment or vLLM/SGLang setup.
NVIDIA Triton Inference Server — model repository, config.pbtxt, ensemble/BLS pipelines, backends (TensorRT/ONNX/Python), dynamic batching, model management API, perf_analyzer. Use when serving models with Triton Inference Server. NOT for K8s deployment patterns. NOT for NIM.
LLM evaluation with lm-evaluation-harness — MMLU, HumanEval, GSM8K benchmarks, custom tasks, vLLM/HF/OpenAI backends, metrics, and LLM-as-judge. Use when evaluating or benchmarking language models. NOT for training, fine-tuning, dataset preprocessing, or model serving.
KubeRay operator — RayCluster, RayJob, RayService, GPU scheduling, autoscaling, auth tokens, Label Selector API, GCS fault tolerance, TLS, observability, and Kueue/Volcano integration. Use when deploying Ray on Kubernetes. NOT for Ray Core programming (see ray-core).
