uv — Ultra-Fast Python Package Manager
Manages Python projects with uv by Astral — the ultra-fast Python package and project manager written in Rust. Covers dependency resolution, virtual environment management, workspace/multirepo setup, build tool integration, CI/CD optimization, and pip compatibility layer for modern Python development workflows.
TL;DR Checklist
When to Use
Use this skill when:
- Setting up a new Python project and wanting maximum dependency resolution speed (10-100x faster than pip/pip-tools/poetry)
- Managing dependency trees across multiple environments (local dev, CI/CD, production) with deterministic lockfiles
- Configuring uv workspaces for monorepo or multi-package Python projects
- Optimizing CI/CD pipelines where dependency installation time is a bottleneck
- Migrating from pip/requirements.txt, pip-tools, Poetry, or pdm to a faster alternative
- Integrating Python tooling (ruff, mypy, pytest) as uv-managed tools rather than project dependencies
When NOT to Use
Avoid this skill for:
- Projects that already have an established Poetry or pdm workflow with no speed pressure — the migration effort may not justify the benefit
- Purely system-level Python management (e.g., OS package managers like apt/yum) — uv manages user-space environments only
- Non-standard build backends requiring custom hooks — uv uses standard PEP 517/621 tooling and may not support exotic build configurations
Core Workflow
Phase 1: Project Initialization
Scaffold a new project — Run uv init <project-name> to create a fully configured project with pyproject.toml, src layout, and a uv.lock file pre-generated.
# Create a new project (auto-generates pyproject.toml + src/ layout)
uv init my-service
cd my-service
# Project structure:
# my-service/
# ├── README.md
# ├── pyproject.toml
# └── src/my_service/__init__.py
# For a script-style project (no package, just executable):
uv init --script my-script.py
Verify the generated pyproject.toml — The scaffold creates a minimal but complete PEP 621 compliant configuration:
[project]
name = "my-service"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Phase 2: Dependency Management
Add production and development dependencies — Use uv add for all dependency operations. Dependencies are resolved atomically against PyPI, written to pyproject.toml, and the lockfile is updated in a single pass.
# Add production dependency (latest compatible version)
uv add httpx
# Pin to specific version range
uv add "pydantic>=2.5,<3"
# Add development-only dependency
uv add --dev pytest ruff mypy
# Add with extras
uv add "psycopg2-binary"
# Add from git repository
uv add "my-lib @ git+https://github.com/user/my-lib.git@main"
# Add local path dependency (for workspace members)
uv add ../shared-utils
# Add optional/extra dependency
uv add --optional async "httpx[socks]"
Configure the complete project manifest — Structure pyproject.toml with production dependencies, dev groups, optional features, and tool configurations:
[project]
name = "api-service"
version = "1.0.0"
description = "High-performance async API service"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"httpx>=0.27",
"pydantic>=2.5,<3",
"sqlalchemy>=2.0,<3",
"structlog>=24.1",
"prometheus-client>=0.20",
]
[project.optional-dependencies]
postgres = ["asyncpg>=0.29"]
cache = ["redis>=5.0"]
[project.scripts]
api-server = "api_service.cli:main"
migrate-db = "api_service.db:migrate"
[tool.uv]
dev-dependencies = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=5.0",
"hypothesis>=6.90",
"ruff>=0.4",
"mypy>=1.8",
"pre-commit>=3.5",
]
[tool.uv.workspace]
members = ["packages/*"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Install/sync all dependencies — uv sync resolves the lockfile and installs all dependencies into the project's virtual environment. This is the primary installation command, replacing pip install entirely.
# Install ALL dependencies (production + dev) from lockfile
uv sync
# Production only (skip dev dependencies)
uv sync --frozen # Use exact versions from lockfile, no resolution
# After adding/updating pyproject.toml without updating lock:
uv lock # Resolve and update lockfile
uv sync # Install resolved dependencies
# Update a specific package to its latest version
uv add --upgrade httpx
uv add --upgrade-package "pydantic"
# Remove a dependency entirely
uv remove structlog
Phase 3: Environment and Tool Management
Manage the virtual environment — uv creates and manages a .venv directory automatically. No manual venv creation or activation needed. Use uv run to execute any command within the managed environment.
# Run any command in the project's virtual environment
uv run pytest tests/ --cov=src --cov-report=term-missing
uv run ruff check .
uv run mypy src/api_service/
uv run api-server --host 0.0.0.0 --port 8000
# Run Python with the correct interpreter and environment
uv run python -c "import sys; print(sys.version)"
# Sync ensures the venv matches pyproject.toml exactly
uv sync
# Remove the venv entirely (will be recreated on next sync)
rm -rf .venv
uv sync # Fresh environment from scratch
# Use a specific Python version (uv installs it automatically if needed)
uv venv --python 3.12
uv sync
# List all installed packages in the current environment
uv pip list
Configure uv as a tool manager — Separate tool installations from project dependencies using uv tool install. This keeps your virtual environment lean and allows running tools system-wide:
# Install tools globally (separate from project dependencies)
uv tool install ruff
uv tool install mypy
uv tool install pytest
uv tool install pre-commit
# Run a tool — available in PATH after install
ruff check .
mypy src/
# Manage installed tools
uv tool list # Show all installed tools
uv tool upgrade --all # Upgrade all tools to latest versions
# Tools can also be run via `uvx` (cross-platform)
uvx ruff check .
uvx mypy src/
# Install a specific version of a tool
uv tool install pre-commit==3.5.0
# Create a script that bundles a tool as a dependency
cat > run-tests <<'EOF'
#!/usr/bin/env -S uv run --with pytest --with pytest-cov
pytest tests/ --cov=src
EOF
chmod +x run-tests
./run-tests # Automatically installs pytest + pytest-cov into ephemeral venv
Phase 4: Workspace (Monorepo) Setup
Configure uv workspaces for multi-package projects — Define a root pyproject.toml that declares workspace members, each with its own dependencies:
# Root pyproject.toml
[project]
name = "monorepo"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[tool.uv.workspace]
members = ["packages/*"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Each workspace member has its own pyproject.toml:
# packages/core/pyproject.toml
[project]
name = "api-core"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"pydantic>=2.5",
"structlog>=24.1",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# packages/api/pyproject.toml
[project]
name = "api-server"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"httpx>=0.27",
"sqlalchemy>=2.0",
{ include-group = "core", name = "api-core" }, # workspace reference
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# packages/cli/pyproject.toml
[project]
name = "api-cli"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
{ include-group = "core", name = "api-core" },
{ include-group = "api", name = "api-server" },
]
[project.scripts]
api-cli = "api_cli.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Checkpoint: Run uv sync from the workspace root — uv resolves all workspace members, creates a single unified lockfile with no inter-package version conflicts, and installs everything into one virtual environment.
Phase 5: Build and Distribution
Build distribution packages — Generate wheel (.whl) and source distribution (sdist) artifacts using standard PEP 517/621 tooling:
# Build both wheel and sdist into dist/ directory
uv build
# Output files:
# dist/api_service-0.1.0-py3-none-any.whl
# dist/api_service-0.1.0.tar.gz
# Build only wheel (faster, preferred for PyPI upload)
uv build --wheel
# Verify the distribution before publishing
twine check dist/*
# Publish to PyPI
uv publish --token $PYPI_TOKEN
# Or use twine directly (works with any build backend)
poetry build && twine check dist/* && twine upload dist/*
Integrate into CI/CD pipelines — Optimize for speed by using frozen lockfile installs and uv's cache:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: "3.12"
# Fast dependency resolution from cached lockfile
- name: Sync dependencies
run: uv sync --frozen
# Run tests with correct environment
- name: Run tests
run: uv run pytest tests/ --cov=src --cov-report=xml
- name: Lint
run: uv run ruff check .
- name: Type check
run: uv run mypy src/
Implementation Patterns
Pattern 1: Complete pyproject.toml for a Production Microservice
[project]
name = "data-pipeline"
version = "2.0.0"
description = "High-throughput async data processing pipeline with configurable connectors"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"httpx>=0.28,<1.0",
"pydantic>=2.10,<3",
"structlog>=24.3",
"click>=8.1",
"pyyaml>=6.0",
]
[project.optional-dependencies]
s3 = ["boto3>=1.35"]
redis = ["redis>=5.0,<6"]
postgres = ["asyncpg>=0.30"]
[project.scripts]
pipeline = "data_pipeline.cli:main"
migrate = "data_pipeline.db:migrate"
[tool.uv]
dev-dependencies = [
"pytest>=8.3",
"pytest-asyncio>=0.24",
"pytest-cov>=5.0",
"hypothesis>=6.110",
"ruff>=0.8",
"mypy>=1.11",
"pre-commit>=4.0",
]
[tool.uv.sources]
# Override a dependency to use a local path (for development)
pydantic = { path = "../pydantic", editable = true }
# Use a specific index URL for private packages
boto3 = { index = "private-pypi" }
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
target-version = "py312"
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
Pattern 2: Dependency Resolution — BAD vs. GOOD Version Constraints
# ❌ BAD — Overly loose constraints cause non-deterministic builds across environments
[project]
dependencies = [
"requests", # No version pin at all!
"httpx>=0.20", # Too wide a range — may pull breaking changes in 0.x
"pydantic==1.0.0", # Exact pin without upper bound — blocks any update ever
]
# ❌ BAD — Using pip-style version specifiers (no uv awareness of resolution strategy)
dependencies = [
"httpx~=0.27", # PEP 440 compatible release is fine, but ~ syntax can be confusing
"pydantic^2.5", # ^ syntax is not valid in PEP 440 — will fail resolution!
]
# ✅ GOOD — PEP 440 compliant constraints with sensible version ranges
[project]
dependencies = [
"httpx>=0.28,<1.0", # Allow minor/patch updates within major version
"pydantic>=2.10,<3", # Major version boundary for API stability
"structlog>=24.1.0", # Specific minimum with no upper bound (safe for well-maintained libs)
]
# ❌ BAD — Conflicting version constraints across the workspace
[project]
name = "service-a"
dependencies = ["httpx>=0.28"]
[project]
name = "service-b"
dependencies = ["httpx==0.27.0"] # Hard conflict with service-a!
# ✅ GOOD — Aligned constraints via workspace-level minimum
[project]
name = "service-a"
dependencies = ["httpx>=0.28,<1.0"]
[project]
name = "service-b"
dependencies = ["httpx>=0.28,<1.0"] # Same constraint — uv resolves to highest compatible
Pattern 3: pip Compatibility Layer (Drop-in Replacement)
uv provides a full pip install compatibility interface, making it a drop-in replacement for any script using pip:
# uv acts as a direct pip replacement — same commands, faster resolution
uv pip install httpx pydantic
uv pip install -r requirements.txt
uv pip freeze > current-deps.txt
# Sync a requirements file exactly (replaces pip-sync from pip-tools)
uv pip sync requirements.txt
# Install from requirements.txt with constraints file
uv pip install -r requirements.txt -c constraints.txt
# Use uv as pip in Docker builds (direct replacement, no venv needed):
# FROM python:3.12-slim
# RUN curl -LsSf https://astral.sh/uv/install.sh | sh
# COPY requirements.txt .
# RUN uv pip install --system -r requirements.txt
# For virtual environments with pip compatibility:
uv venv .venv
source .venv/bin/activate # Or use `uv run` to skip activation entirely
uv pip install httpx pydantic
Pattern 4: CI/CD Optimization — From 4 Minutes to 30 Seconds
# ❌ SLOW — Standard pip + requirements.txt flow (typical CI time)
pip install --upgrade pip # ~5 seconds
pip install -r requirements.txt # ~2-3 minutes (slow resolution)
pip install pytest ruff mypy # Additional packages: ~1 minute
pytest tests/ # Run tests
# ✅ FAST — uv flow (typical CI time)
curl -LsSf https://astral.sh/uv/install.sh | sh # ~2 seconds (cached by setup-uv action)
uv sync --frozen # ~5-10 seconds (uses pre-cached resolution)
uv run pytest tests/ --cov=src # Execute in managed venv
# Even faster: cache the uv cache directory between CI runs
# In GitHub Actions:
# - uses: actions/cache@v4
# with:
# path: ~/.cache/uv
# key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}
Constraints
MUST DO
- Commit
uv.lock to version control — this is the single source of truth for reproducible builds across all environments and CI runners
- Use
requires-python = ">=X.Y" to pin the minimum Python version in pyproject.toml (e.g., ">=3.12")
- Use PEP 440 version specifiers (
>=, <, ~=) — never use Poetry's ^ or ~ syntax (those are not valid PEP 440)
- Run
uv sync --frozen in CI to enforce exact lockfile versions without network resolution
- Use
uv run <command> for all project commands — never manually activate .venv or rely on system Python
- Separate tool installations (
uv tool install) from project dependencies to keep environments lean
- Validate distributions with
twine check dist/* before publishing to any registry
- Pin
requires-python consistently across all workspace member packages
MUST NOT DO
- Edit
uv.lock manually — always regenerate with uv lock, even after single dependency changes
- Mix
pip install directly with uv-managed environments — this bypasses the lockfile and corrupts the dependency tree
- Commit pyproject.toml without a matching uv.lock — future builds will be non-deterministic
- Use Poetry's
^ version constraint syntax in pyproject.toml — uv follows PEP 440, not Poetry's resolver
- Run
uv pip install inside an active virtual environment — use uv sync at the project root instead
- Remove uv.lock to "fix" dependency conflicts — adjust version constraints in pyproject.toml and re-resolve with
uv lock
Output Template
When configuring or auditing a uv-managed project, produce:
- Dependency Audit — List all production and dev dependencies with resolved versions from uv.lock, flagging any overly loose version constraints or potential conflicts
- pyproject.toml Review — Validate structure: presence of
[project], requires-python, dependency lists, tool configurations, build-system specification
- Lockfile Consistency Check — Verify uv.lock matches pyproject.toml; report if manual edits may have drifted the lockfile from the manifest
- Workspace Analysis — For monorepo setups: confirm all workspace members declared in
[tool.uv.workspace], cross-references use proper dependency specifications, no inter-package conflicts
- CI/CD Pipeline Audit — Confirm
uv sync --frozen is used, cache configuration for .cache/uv exists, and tool installations are separated from project dependencies
Related Skills
| Skill |
Purpose |
poetry |
Poetry alternative — different resolver and plugin ecosystem but similar workflow patterns |
package-ecosystem-navigator |
General package manager ecosystem comparison (npm, pypi, cargo, pip-tools) |
dependency-supply-chain-security |
Dependency security auditing, CVE scanning, and supply chain protections |
Live References
Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.
1---2name: python-uv3description: Manages Python projects with uv by Astral — ultra-fast dependency resolution, virtual environments, workspace/multirepo setup, build tools, and pip compatibility for modern Python development workflows.4license: MIT5---678910# uv — Ultra-Fast Python Package Manager1112Manages Python projects with uv by Astral — the ultra-fast Python package and project manager written in Rust. Covers dependency resolution, virtual environment management, workspace/multirepo setup, build tool integration, CI/CD optimization, and pip compatibility layer for modern Python development workflows.1314## TL;DR Checklist1516- [ ] Use `uv init <project>` to scaffold a new project — generates pyproject.toml with src layout17- [ ] Always commit `uv.lock` for reproducible builds across environments and CI runners18- [ ] Use `uv add <pkg>` to install dependencies (never pip install in uv-managed projects)19- [ ] Pin Python version with `requires-python = ">=3.12"` in pyproject.toml20- [ ] Use `uv sync` instead of `pip install` — resolves and installs from lockfile atomically21- [ ] Use `uv run <command>` to execute scripts within the project's environment22- [ ] Configure workspaces with `[tool.uv.workspace]` for multi-package monorepo setups2324---2526## When to Use2728Use this skill when:2930- Setting up a new Python project and wanting maximum dependency resolution speed (10-100x faster than pip/pip-tools/poetry)31- Managing dependency trees across multiple environments (local dev, CI/CD, production) with deterministic lockfiles32- Configuring uv workspaces for monorepo or multi-package Python projects33- Optimizing CI/CD pipelines where dependency installation time is a bottleneck34- Migrating from pip/requirements.txt, pip-tools, Poetry, or pdm to a faster alternative35- Integrating Python tooling (ruff, mypy, pytest) as uv-managed tools rather than project dependencies3637## When NOT to Use3839Avoid this skill for:4041- Projects that already have an established Poetry or pdm workflow with no speed pressure — the migration effort may not justify the benefit42- Purely system-level Python management (e.g., OS package managers like apt/yum) — uv manages user-space environments only43- Non-standard build backends requiring custom hooks — uv uses standard PEP 517/621 tooling and may not support exotic build configurations4445---4647## Core Workflow4849### Phase 1: Project Initialization50511. **Scaffold a new project** — Run `uv init <project-name>` to create a fully configured project with pyproject.toml, src layout, and a uv.lock file pre-generated.52 ```bash53 # Create a new project (auto-generates pyproject.toml + src/ layout)54 uv init my-service55 cd my-service5657 # Project structure:58 # my-service/59 # ├── README.md60 # ├── pyproject.toml61 # └── src/my_service/__init__.py6263 # For a script-style project (no package, just executable):64 uv init --script my-script.py65 ```66672. **Verify the generated pyproject.toml** — The scaffold creates a minimal but complete PEP 621 compliant configuration:68 ```toml69 [project]70 name = "my-service"71 version = "0.1.0"72 description = "Add your description here"73 readme = "README.md"74 requires-python = ">=3.12"75 dependencies = []7677 [build-system]78 requires = ["hatchling"]79 build-backend = "hatchling.build"80 ```8182### Phase 2: Dependency Management83843. **Add production and development dependencies** — Use `uv add` for all dependency operations. Dependencies are resolved atomically against PyPI, written to pyproject.toml, and the lockfile is updated in a single pass.85 ```bash86 # Add production dependency (latest compatible version)87 uv add httpx8889 # Pin to specific version range90 uv add "pydantic>=2.5,<3"9192 # Add development-only dependency93 uv add --dev pytest ruff mypy9495 # Add with extras96 uv add "psycopg2-binary"9798 # Add from git repository99 uv add "my-lib @ git+https://github.com/user/my-lib.git@main"100101 # Add local path dependency (for workspace members)102 uv add ../shared-utils103104 # Add optional/extra dependency105 uv add --optional async "httpx[socks]"106 ```1071084. **Configure the complete project manifest** — Structure pyproject.toml with production dependencies, dev groups, optional features, and tool configurations:109 ```toml110 [project]111 name = "api-service"112 version = "1.0.0"113 description = "High-performance async API service"114 readme = "README.md"115 requires-python = ">=3.12"116 dependencies = [117 "httpx>=0.27",118 "pydantic>=2.5,<3",119 "sqlalchemy>=2.0,<3",120 "structlog>=24.1",121 "prometheus-client>=0.20",122 ]123124 [project.optional-dependencies]125 postgres = ["asyncpg>=0.29"]126 cache = ["redis>=5.0"]127128 [project.scripts]129 api-server = "api_service.cli:main"130 migrate-db = "api_service.db:migrate"131132 [tool.uv]133 dev-dependencies = [134 "pytest>=8.0",135 "pytest-asyncio>=0.23",136 "pytest-cov>=5.0",137 "hypothesis>=6.90",138 "ruff>=0.4",139 "mypy>=1.8",140 "pre-commit>=3.5",141 ]142143 [tool.uv.workspace]144 members = ["packages/*"]145146 [build-system]147 requires = ["hatchling"]148 build-backend = "hatchling.build"149 ```1501515. **Install/sync all dependencies** — `uv sync` resolves the lockfile and installs all dependencies into the project's virtual environment. This is the primary installation command, replacing pip install entirely.152 ```bash153 # Install ALL dependencies (production + dev) from lockfile154 uv sync155156 # Production only (skip dev dependencies)157 uv sync --frozen # Use exact versions from lockfile, no resolution158159 # After adding/updating pyproject.toml without updating lock:160 uv lock # Resolve and update lockfile161 uv sync # Install resolved dependencies162163 # Update a specific package to its latest version164 uv add --upgrade httpx165 uv add --upgrade-package "pydantic"166167 # Remove a dependency entirely168 uv remove structlog169 ```170171### Phase 3: Environment and Tool Management1721736. **Manage the virtual environment** — uv creates and manages a `.venv` directory automatically. No manual venv creation or activation needed. Use `uv run` to execute any command within the managed environment.174 ```bash175 # Run any command in the project's virtual environment176 uv run pytest tests/ --cov=src --cov-report=term-missing177 uv run ruff check .178 uv run mypy src/api_service/179 uv run api-server --host 0.0.0.0 --port 8000180181 # Run Python with the correct interpreter and environment182 uv run python -c "import sys; print(sys.version)"183184 # Sync ensures the venv matches pyproject.toml exactly185 uv sync186187 # Remove the venv entirely (will be recreated on next sync)188 rm -rf .venv189 uv sync # Fresh environment from scratch190191 # Use a specific Python version (uv installs it automatically if needed)192 uv venv --python 3.12193 uv sync194195 # List all installed packages in the current environment196 uv pip list197 ```1981997. **Configure uv as a tool manager** — Separate tool installations from project dependencies using `uv tool install`. This keeps your virtual environment lean and allows running tools system-wide:200 ```bash201 # Install tools globally (separate from project dependencies)202 uv tool install ruff203 uv tool install mypy204 uv tool install pytest205 uv tool install pre-commit206207 # Run a tool — available in PATH after install208 ruff check .209 mypy src/210211 # Manage installed tools212 uv tool list # Show all installed tools213 uv tool upgrade --all # Upgrade all tools to latest versions214215 # Tools can also be run via `uvx` (cross-platform)216 uvx ruff check .217 uvx mypy src/218219 # Install a specific version of a tool220 uv tool install pre-commit==3.5.0221222 # Create a script that bundles a tool as a dependency223 cat > run-tests <<'EOF'224 #!/usr/bin/env -S uv run --with pytest --with pytest-cov225 pytest tests/ --cov=src226 EOF227 chmod +x run-tests228 ./run-tests # Automatically installs pytest + pytest-cov into ephemeral venv229 ```230231### Phase 4: Workspace (Monorepo) Setup2322338. **Configure uv workspaces for multi-package projects** — Define a root pyproject.toml that declares workspace members, each with its own dependencies:234 ```toml235 # Root pyproject.toml236 [project]237 name = "monorepo"238 version = "0.1.0"239 requires-python = ">=3.12"240 dependencies = []241242 [tool.uv.workspace]243 members = ["packages/*"]244245 [build-system]246 requires = ["hatchling"]247 build-backend = "hatchling.build"248 ```249250 Each workspace member has its own pyproject.toml:251 ```toml252 # packages/core/pyproject.toml253 [project]254 name = "api-core"255 version = "0.1.0"256 requires-python = ">=3.12"257 dependencies = [258 "pydantic>=2.5",259 "structlog>=24.1",260 ]261262 [build-system]263 requires = ["hatchling"]264 build-backend = "hatchling.build"265266 # packages/api/pyproject.toml267 [project]268 name = "api-server"269 version = "0.1.0"270 requires-python = ">=3.12"271 dependencies = [272 "httpx>=0.27",273 "sqlalchemy>=2.0",274 { include-group = "core", name = "api-core" }, # workspace reference275 ]276277 [build-system]278 requires = ["hatchling"]279 build-backend = "hatchling.build"280281 # packages/cli/pyproject.toml282 [project]283 name = "api-cli"284 version = "0.1.0"285 requires-python = ">=3.12"286 dependencies = [287 { include-group = "core", name = "api-core" },288 { include-group = "api", name = "api-server" },289 ]290291 [project.scripts]292 api-cli = "api_cli.cli:main"293294 [build-system]295 requires = ["hatchling"]296 build-backend = "hatchling.build"297 ```298299 **Checkpoint:** Run `uv sync` from the workspace root — uv resolves all workspace members, creates a single unified lockfile with no inter-package version conflicts, and installs everything into one virtual environment.300301### Phase 5: Build and Distribution3023039. **Build distribution packages** — Generate wheel (.whl) and source distribution (sdist) artifacts using standard PEP 517/621 tooling:304 ```bash305 # Build both wheel and sdist into dist/ directory306 uv build307308 # Output files:309 # dist/api_service-0.1.0-py3-none-any.whl310 # dist/api_service-0.1.0.tar.gz311312 # Build only wheel (faster, preferred for PyPI upload)313 uv build --wheel314315 # Verify the distribution before publishing316 twine check dist/*317318 # Publish to PyPI319 uv publish --token $PYPI_TOKEN320321 # Or use twine directly (works with any build backend)322 poetry build && twine check dist/* && twine upload dist/*323 ```32432510. **Integrate into CI/CD pipelines** — Optimize for speed by using frozen lockfile installs and uv's cache:326 ```yaml327 # .github/workflows/ci.yml328 name: CI329 on: [push, pull_request]330331 jobs:332 test:333 runs-on: ubuntu-latest334 steps:335 - uses: actions/checkout@v4336337 - name: Install uv338 uses: astral-sh/setup-uv@v3339 with:340 python-version: "3.12"341342 # Fast dependency resolution from cached lockfile343 - name: Sync dependencies344 run: uv sync --frozen345346 # Run tests with correct environment347 - name: Run tests348 run: uv run pytest tests/ --cov=src --cov-report=xml349350 - name: Lint351 run: uv run ruff check .352353 - name: Type check354 run: uv run mypy src/355 ```356357---358359## Implementation Patterns360361### Pattern 1: Complete pyproject.toml for a Production Microservice362363```toml364[project]365name = "data-pipeline"366version = "2.0.0"367description = "High-throughput async data processing pipeline with configurable connectors"368readme = "README.md"369requires-python = ">=3.12"370dependencies = [371 "httpx>=0.28,<1.0",372 "pydantic>=2.10,<3",373 "structlog>=24.3",374 "click>=8.1",375 "pyyaml>=6.0",376]377378[project.optional-dependencies]379s3 = ["boto3>=1.35"]380redis = ["redis>=5.0,<6"]381postgres = ["asyncpg>=0.30"]382383[project.scripts]384pipeline = "data_pipeline.cli:main"385migrate = "data_pipeline.db:migrate"386387[tool.uv]388dev-dependencies = [389 "pytest>=8.3",390 "pytest-asyncio>=0.24",391 "pytest-cov>=5.0",392 "hypothesis>=6.110",393 "ruff>=0.8",394 "mypy>=1.11",395 "pre-commit>=4.0",396]397398[tool.uv.sources]399# Override a dependency to use a local path (for development)400pydantic = { path = "../pydantic", editable = true }401402# Use a specific index URL for private packages403boto3 = { index = "private-pypi" }404405[build-system]406requires = ["hatchling"]407build-backend = "hatchling.build"408409[tool.ruff]410target-version = "py312"411line-length = 100412413[tool.ruff.lint]414select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]415416[tool.ruff.format]417quote-style = "double"418indent-style = "space"419420[tool.pytest.ini_options]421asyncio_mode = "auto"422testpaths = ["tests"]423424[tool.mypy]425python_version = "3.12"426strict = true427warn_return_any = true428429[[tool.mypy.overrides]]430module = "tests.*"431disallow_untyped_defs = false432```433434### Pattern 2: Dependency Resolution — BAD vs. GOOD Version Constraints435436```toml437# ❌ BAD — Overly loose constraints cause non-deterministic builds across environments438[project]439dependencies = [440 "requests", # No version pin at all!441 "httpx>=0.20", # Too wide a range — may pull breaking changes in 0.x442 "pydantic==1.0.0", # Exact pin without upper bound — blocks any update ever443]444445# ❌ BAD — Using pip-style version specifiers (no uv awareness of resolution strategy)446dependencies = [447 "httpx~=0.27", # PEP 440 compatible release is fine, but ~ syntax can be confusing448 "pydantic^2.5", # ^ syntax is not valid in PEP 440 — will fail resolution!449]450451# ✅ GOOD — PEP 440 compliant constraints with sensible version ranges452[project]453dependencies = [454 "httpx>=0.28,<1.0", # Allow minor/patch updates within major version455 "pydantic>=2.10,<3", # Major version boundary for API stability456 "structlog>=24.1.0", # Specific minimum with no upper bound (safe for well-maintained libs)457]458459# ❌ BAD — Conflicting version constraints across the workspace460[project]461name = "service-a"462dependencies = ["httpx>=0.28"]463464[project]465name = "service-b" 466dependencies = ["httpx==0.27.0"] # Hard conflict with service-a!467468# ✅ GOOD — Aligned constraints via workspace-level minimum469[project]470name = "service-a"471dependencies = ["httpx>=0.28,<1.0"]472473[project]474name = "service-b"475dependencies = ["httpx>=0.28,<1.0"] # Same constraint — uv resolves to highest compatible476```477478### Pattern 3: pip Compatibility Layer (Drop-in Replacement)479480uv provides a full `pip install` compatibility interface, making it a drop-in replacement for any script using pip:481482```bash483# uv acts as a direct pip replacement — same commands, faster resolution484uv pip install httpx pydantic485uv pip install -r requirements.txt486uv pip freeze > current-deps.txt487488# Sync a requirements file exactly (replaces pip-sync from pip-tools)489uv pip sync requirements.txt490491# Install from requirements.txt with constraints file492uv pip install -r requirements.txt -c constraints.txt493494# Use uv as pip in Docker builds (direct replacement, no venv needed):495# FROM python:3.12-slim496# RUN curl -LsSf https://astral.sh/uv/install.sh | sh497# COPY requirements.txt .498# RUN uv pip install --system -r requirements.txt499500# For virtual environments with pip compatibility:501uv venv .venv502source .venv/bin/activate # Or use `uv run` to skip activation entirely503uv pip install httpx pydantic504```505506### Pattern 4: CI/CD Optimization — From 4 Minutes to 30 Seconds507508```bash509# ❌ SLOW — Standard pip + requirements.txt flow (typical CI time)510pip install --upgrade pip # ~5 seconds511pip install -r requirements.txt # ~2-3 minutes (slow resolution)512pip install pytest ruff mypy # Additional packages: ~1 minute513pytest tests/ # Run tests514515# ✅ FAST — uv flow (typical CI time)516curl -LsSf https://astral.sh/uv/install.sh | sh # ~2 seconds (cached by setup-uv action)517uv sync --frozen # ~5-10 seconds (uses pre-cached resolution)518uv run pytest tests/ --cov=src # Execute in managed venv519520# Even faster: cache the uv cache directory between CI runs521# In GitHub Actions:522# - uses: actions/cache@v4523# with:524# path: ~/.cache/uv525# key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}526```527528---529530## Constraints531532### MUST DO533- Commit `uv.lock` to version control — this is the single source of truth for reproducible builds across all environments and CI runners534- Use `requires-python = ">=X.Y"` to pin the minimum Python version in pyproject.toml (e.g., `">=3.12"`)535- Use PEP 440 version specifiers (`>=`, `<`, `~=`) — never use Poetry's `^` or `~` syntax (those are not valid PEP 440)536- Run `uv sync --frozen` in CI to enforce exact lockfile versions without network resolution537- Use `uv run <command>` for all project commands — never manually activate `.venv` or rely on system Python538- Separate tool installations (`uv tool install`) from project dependencies to keep environments lean539- Validate distributions with `twine check dist/*` before publishing to any registry540- Pin `requires-python` consistently across all workspace member packages541542### MUST NOT DO543- Edit `uv.lock` manually — always regenerate with `uv lock`, even after single dependency changes544- Mix `pip install` directly with uv-managed environments — this bypasses the lockfile and corrupts the dependency tree545- Commit pyproject.toml without a matching uv.lock — future builds will be non-deterministic546- Use Poetry's `^` version constraint syntax in pyproject.toml — uv follows PEP 440, not Poetry's resolver547- Run `uv pip install` inside an active virtual environment — use `uv sync` at the project root instead548- Remove uv.lock to "fix" dependency conflicts — adjust version constraints in pyproject.toml and re-resolve with `uv lock`549550---551552## Output Template553554When configuring or auditing a uv-managed project, produce:5555561. **Dependency Audit** — List all production and dev dependencies with resolved versions from uv.lock, flagging any overly loose version constraints or potential conflicts5572. **pyproject.toml Review** — Validate structure: presence of `[project]`, `requires-python`, dependency lists, tool configurations, build-system specification5583. **Lockfile Consistency Check** — Verify uv.lock matches pyproject.toml; report if manual edits may have drifted the lockfile from the manifest5594. **Workspace Analysis** — For monorepo setups: confirm all workspace members declared in `[tool.uv.workspace]`, cross-references use proper dependency specifications, no inter-package conflicts5605. **CI/CD Pipeline Audit** — Confirm `uv sync --frozen` is used, cache configuration for `.cache/uv` exists, and tool installations are separated from project dependencies561562---563564## Related Skills565566| Skill | Purpose |567|---|---|568| `poetry` | Poetry alternative — different resolver and plugin ecosystem but similar workflow patterns |569| `package-ecosystem-navigator` | General package manager ecosystem comparison (npm, pypi, cargo, pip-tools) |570| `dependency-supply-chain-security` | Dependency security auditing, CVE scanning, and supply chain protections |571572---573574## Live References575576> Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.577578- [uv Documentation](https://docs.astral.sh/uv/)579- [uv Project Management Guide](https://docs.astral.sh/uv/guides/projects/)580- [uv Workspaces (Monorepo Support)](https://docs.astral.sh/uv/workspaces/)581- [uv Tool Management](https://docs.astral.sh/uv/guides/tools/)582- [PEP 621 — Storing Project Metadata in pyproject.toml](https://peps.python.org/pep-0621/)583- [PEP 440 — Version Specification and Comparison](https://peps.python.org/pep-0440/)584- [Twine — PyPI Package Upload Tool](https://twine.readthedocs.io/)