Python Monorepo Management — Core Concepts

What Is a Python Monorepo?

A monorepo stores multiple Python packages — libraries, services, CLI tools — in a single version-controlled repository. Each package has its own pyproject.toml and can be versioned, tested, and released independently, but they share CI infrastructure, linting rules, and developer tooling.

Why Teams Choose Monorepos

Atomic Cross-Package Changes

When a shared library changes its API, every dependent service updates in the same commit. There is no “publish version 2.0, then chase down six repos to upgrade” cycle. Code review covers the full blast radius.

Shared Tooling Configuration

Ruff, mypy, and pre-commit configs live at the root. Individual packages inherit these settings, reducing configuration drift across dozens of projects.

Simplified Dependency Graphs

Internal packages reference each other by path instead of by published version. A service can depend on the latest commit of an internal library without waiting for a PyPI release.

Typical Structure

company-mono/
├── packages/
│   ├── auth-service/
│   │   ├── src/auth_service/
│   │   ├── tests/
│   │   └── pyproject.toml
│   ├── billing-service/
│   │   ├── src/billing_service/
│   │   ├── tests/
│   │   └── pyproject.toml
│   └── shared-models/
│       ├── src/shared_models/
│       ├── tests/
│       └── pyproject.toml
├── pyproject.toml          # workspace config
├── ruff.toml               # shared lint rules
└── .github/workflows/
    └── ci.yml

Workspace Tooling

Hatch Workspaces

Hatch treats each sub-directory with a pyproject.toml as a workspace member. Running hatch test from the root can execute tests across all packages, while hatch build -t wheel packages/auth-service targets a single package.

uv Workspaces

uv (from Astral, the makers of Ruff) supports workspace resolution natively. A root pyproject.toml declares members, and uv sync resolves dependencies across all packages in one lockfile — fast enough to run on every commit.

Pants and Bazel

For larger monorepos (50+ packages), build systems like Pants or Bazel provide dependency graph analysis. They determine which packages are affected by a code change and run only those tests, cutting CI time from hours to minutes.

Selective CI

The biggest monorepo pitfall is CI that rebuilds everything on every push. Solutions:

  • Path filters — GitHub Actions paths: or GitLab rules: changes: triggers CI only when relevant directories change.
  • Affected-package detection — tools like Pants compute the transitive dependency graph and test only affected targets.
  • Layered caching — cache dependency installs per package hash so unchanged packages skip installation entirely.

Common Misconception

“Monorepos mean everyone works on everything.” Access boundaries still exist. GitHub CODEOWNERS files assign review responsibility per directory, and CI can enforce that changes to packages/billing-service/ require approval from the billing team. A monorepo centralizes code, not ownership.

When Not to Use a Monorepo

  • Completely unrelated projects with different teams and release cadences gain little from proximity.
  • Organizations without CI infrastructure to handle selective builds will suffer slow pipelines.
  • Open-source libraries that external contributors clone independently are easier to manage as separate repos.

The one thing to remember: A Python monorepo pays off when packages share dependencies and change together — invest in workspace tooling and selective CI to keep it manageable.

pythonmonorepotooling

See Also

  • Python Black Formatter Understand Black Formatter through a practical analogy so your Python decisions become faster and clearer.
  • Python Bumpversion Release Change your software's version number in every file at once with a single command — no more find-and-replace mistakes.
  • Python Changelog Automation Let your git commits write the changelog so you never forget what changed in a release.
  • Python Ci Cd Python Understand CI CD Python through a practical analogy so your Python decisions become faster and clearer.
  • Python Cicd Pipelines Use Python CI/CD pipelines to remove setup chaos so Python projects stay predictable for every teammate.