2025, Dec 08 01:00

uv workspaces and missing subpackage dependencies: why uv sync skips them and how to fix it

Learn why uv sync installs only root deps in monorepos, causing subpackage dependencies to be missing, and how to fix it via sources or --all-packages.

uv workspaces and “missing” subpackage dependencies: what’s going on and how to fix it

When setting up a Python monorepo with uv, it’s easy to assume that running uv sync at the top level will pull in dependencies for every workspace member. In practice you may see only the root project’s dependencies installed, while the subpackages’ requirements are skipped. Below is a minimal, reproducible layout that shows the behavior and two precise ways to make uv install everything you expect.

A minimal monorepo that reproduces the behavior

The repository hosts a root project and three internal packages: a core library, a pipeline orchestrator, and a dbt bundle. Running uv sync in the root installs only the root deps; dbt-core, dbt-clickhouse, and apache-airflow from the subpackages do not appear.

forge-hub/
├── pyproject.toml
└── modules/
   ├── core-kernel/
   │ └── pyproject.toml
   ├── pipeline-scheduler/
   │ └── pyproject.toml
   └── analytics/
     └── dbt_crafter/
       └── pyproject.toml

Root pyproject.toml:

[project]
name = "forge-hub"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["pandas", "sqlalchemy", "tabulate"]
[tool.uv.workspace]
members = [
    "modules/core-kernel",
    "modules/pipeline-scheduler",
    "modules/analytics/dbt_crafter",
]

Subpackages:

# modules/core-kernel/pyproject.toml
[project]
name = "core-kernel"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["dbt-core", "dbt-clickhouse"]
# modules/pipeline-scheduler/pyproject.toml
[project]
name = "pipeline-scheduler"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["core-kernel", "apache-airflow"]
# modules/analytics/dbt_crafter/pyproject.toml
[project]
name = "dbt-crafter"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["dbt-core", "dbt-clickhouse"]

What actually happens when you run uv sync at the root

Executing uv sync in the repository root installs the dependencies declared by the root project. The subpackages listed in the workspace are recognized as members, but their dependency sets are not installed just because they exist in the workspace. That’s why you end up with pandas, sqlalchemy, and tabulate present, while dbt-core, dbt-clickhouse, and apache-airflow are missing.

The fix: two exact ways to install subpackage dependencies

You can resolve this in one of two ways. The first approach is to declare your subpackages as dependencies of the root project and point those names to the local workspace members. This makes uv bring their dependency trees into the environment when you sync at the root.

[project]
name = "forge-hub"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "core-kernel",
  "pipeline-scheduler",
  "dbt-crafter",
  "pandas",
  "sqlalchemy",
  "tabulate"
]
[tool.uv.workspace]
members = [
    "modules/core-kernel",
    "modules/pipeline-scheduler",
    "modules/analytics/dbt_crafter",
]
[tool.uv.sources]
core-kernel = { workspace = true }
pipeline-scheduler = { workspace = true }
dbt-crafter = { workspace = true }

The second approach is to tell uv explicitly to install dependencies for all workspace packages when syncing from the root. This is a one-shot command and does not require changing your pyproject configuration.

uv sync --all-packages

Why this matters in day-to-day work

If you only sync the root, your environment will not contain the libraries required by subpackages. That means imports from those components will fail until you either declare the subpackages as root dependencies or use the all-packages switch to install everything at once. Keeping this in mind prevents surprises when bootstrapping the repo on a fresh machine or preparing an environment for development and execution.

Takeaways

In a uv workspace, running uv sync at the top level installs the root project’s requirements. To bring in subpackage dependencies, either list the subpackages in the root project’s dependencies and map them via [tool.uv.sources], or use uv sync --all-packages. Choose the option that best matches how you want environments to be created in your monorepo, and you’ll avoid missing dependencies for workspace members.