uv-workspaces

SKILL.md

UV Workspaces

Quick reference for managing monorepo and multi-package projects with UV workspaces.

When to Use This Skill

Use this skill when... Use another skill instead when...
Setting up a Python monorepo with shared deps Managing a single package (uv-project-management)
Configuring workspace members and inter-package deps Adding git/URL dependencies (uv-advanced-dependencies)
Using --package or --all-packages flags Building/publishing to PyPI (python-packaging)
Creating virtual workspaces (root with no project) Managing Python versions (uv-python-versions)
Debugging workspace dependency resolution Running standalone scripts (uv-run)

Quick Reference

Workspace Structure

my-workspace/
├── pyproject.toml          # Root workspace config
├── uv.lock                 # Shared lockfile (all members)
├── packages/
│   ├── core/
│   │   ├── pyproject.toml
│   │   └── src/core/
│   ├── api/
│   │   ├── pyproject.toml
│   │   └── src/api/
│   └── cli/
│       ├── pyproject.toml
│       └── src/cli/
└── README.md

Root pyproject.toml

[project]
name = "my-workspace"
version = "0.1.0"
requires-python = ">=3.11"

[tool.uv.workspace]
members = ["packages/*"]

# Optional: exclude specific members
exclude = ["packages/experimental"]

Virtual Workspace (No Root Package)

When the root is purely organizational and not a package itself, omit the [project] table:

# Root pyproject.toml — virtual workspace (no [project] table)
[tool.uv.workspace]
members = ["packages/*"]
  • The root is not a workspace member
  • All members live in subdirectories
  • uv run and uv sync require --package or --all-packages (will error without them)

Member pyproject.toml

[project]
name = "my-api"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "my-core",       # Workspace member
    "fastapi",       # External (PyPI)
]

[tool.uv.sources]
my-core = { workspace = true }

Common Commands

Operation Command
Sync workspace root uv sync
Sync all members uv sync --all-packages
Sync specific member uv sync --package my-api
Run in member context uv run --package my-api python script.py
Lock entire workspace uv lock
Upgrade a dependency uv lock --upgrade-package requests
Build specific package uv build --package my-core
Add dep to member cd packages/api && uv add requests
Add workspace dep cd packages/api && uv add ../core

Key Behaviors

Source Inheritance

Root tool.uv.sources apply to all members unless overridden.

Use case: Define workspace sources in root for all members, override only when a specific member needs a different version:

# Root pyproject.toml — applies to all members
[tool.uv.sources]
my-utils = { workspace = true }

# packages/legacy/pyproject.toml — needs pinned version
[tool.uv.sources]
my-utils = { path = "../utils-v1" }  # Overrides root entirely

Override is per-dependency and total — if a member defines a source for a dependency, the root source for that dependency is ignored completely.

requires-python Resolution

The workspace enforces the intersection of all members' requires-python:

# packages/core: requires-python = ">=3.10"
# packages/api:  requires-python = ">=3.11"
# Effective:     requires-python = ">=3.11"

All members must have compatible Python version requirements.

Editable Installations

Workspace member dependencies are always editable — source changes are immediately available without reinstallation.

Default Scope

Command Default scope Override
uv lock Entire workspace
uv sync Workspace root only --package, --all-packages
uv run Workspace root only --package, --all-packages
uv build All members --package

Workspace vs Path Dependencies

Feature { workspace = true } { path = "../pkg" }
Shared lockfile Yes No
Always editable Yes Optional
Must be workspace member Yes No
--package flag works Yes No
Conflicting deps allowed No Yes

Use path dependencies when members need conflicting requirements or separate virtual environments.

Docker Layer Caching

# Install deps first (cached layer)
COPY pyproject.toml uv.lock packages/*/pyproject.toml ./
RUN uv sync --frozen --no-install-workspace

# Then install project (changes frequently)
COPY . .
RUN uv sync --frozen
Flag Effect
--no-install-project Skip current project, install deps only
--no-install-workspace Skip all workspace members, install deps only
--no-install-package <name> Skip specific package(s)
--frozen Skip lockfile freshness check

Agentic Optimizations

Context Command
Sync all members uv sync --all-packages
CI sync (frozen) uv sync --all-packages --frozen
Test specific member uv run --package my-core pytest --dots --bail=1
Test all members uv run --all-packages pytest --dots --bail=1
Lock with upgrade uv lock --upgrade-package <dep>
Build one package uv build --package my-core
Docker deps layer uv sync --frozen --no-install-workspace

See Also

  • uv-project-management — Managing individual packages
  • uv-advanced-dependencies — Path and Git dependencies
  • python-packaging — Building and publishing workspace packages

For detailed workspace patterns (virtual workspaces, Docker integration, source inheritance, syncing strategies), CI/CD examples, and troubleshooting, see REFERENCE.md.

Weekly Installs
57
GitHub Stars
13
First Seen
Jan 28, 2026
Installed on
codex54
opencode54
github-copilot53
gemini-cli52
cursor52
cline51