# python-polylith: the Polylith architecture as Python tooling

> Polylith is a components first architecture for monorepos, and this repository is the Python tooling for it, shipped as a Poetry plugin, a standalone CLI and build hooks for Hatch and PDM so that a team can share code between services without turning the repository into a single deployable unit.

**DavidVujic/python-polylith** — Tooling support for the Polylith Architecture in Python.

- Repository: https://github.com/DavidVujic/python-polylith
- Website: https://davidvujic.github.io/python-polylith-docs/
- Stars: 553 · Forks: 32
- Language: Python
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/davidvujic-python-polylith

## A components first architecture, and the tooling to run it

Polylith is an architecture, with tooling support, that was originally built for Clojure, and this repository brings Polylith to Python. The architecture itself is described as applying functional thinking at the system scale, to help build simple, maintainable, testable and scalable backend systems.

The mental model in the readme is a set of building blocks, much like LEGO bricks, and it is components first. All code lives in a monorepo and is available for reuse, and the Python code, the bricks, is separated from the infrastructure and from the actual building of artefacts.

That separation is the point of the whole thing. In a conventional monorepo, sharing code between services tends to mean a shared library that everything depends on, and the services stop being independently deployable. In Polylith, a component is a small piece of code that two services can both use, and each service is still assembled from components into its own artefact.

The stated main use case is having one or more microservices, or apps, in a monorepo and sharing code between the services. The secondary use case, which the readme notes is not the main one, is building libraries to be published on PyPI.

So the audience is a specific kind of Python team: several services, one repository, and a shared vocabulary that makes the sharing explicit. The tooling exists to make that workable across the package managers Python teams actually use.

## Bases, components and the workspace file

The repository layout of the tooling project itself mirrors the architecture it supports, which is the clearest way to see the concepts.

There is a bases directory and a components directory, and the packaging manifest splits the code between them.

```toml
[tool.poetry]
name = "python-polylith"
version = "0.0.2"
description = "A Python Polylith repo adding tooling support for the Polylith Architecture"
authors = ["David Vujic"]
homepage = "https://github.com/davidvujic/python-polylith"
repository = "https://github.com/davidvujic/python-polylith"
readme = "README.md"
packages = [
    { include = "polylith/poetry_plugin", from = "bases" },
    { include = "polylith/cli", from = "bases" },
    { include = "polylith/hatch_hooks", from = "bases" },
    { include = "polylith/pdm_project_hooks", from = "bases" },
    { include = "polylith/pdm_workspace_hooks", from = "bases" },
```

The bases are the entry points, the things a user actually invokes: the Poetry plugin, the CLI, the Hatch hooks and the two PDM hooks. The components are the machinery those entry points call, and the manifest then lists them: alias, bricks, building, check, configuration, commands, deps, development, diff, dirs, distributions, environment, files, hatch, imports, info, interactive, interface, libs and output, among others.

The architectural idea is visible in the names. There is a bricks component, which is the unit of code, and separate components for building artefacts, for checking the workspace, for working out dependencies between bricks, and for diffing. A command such as diff is a component in its own right, which is what keeps the tool testable and lets the same logic serve the plugin and the CLI.

At the top level of the repository there are the usual Polylith directories, bases, components, development, projects and test, plus a workspace.toml, a poetry.toml and a mypy.ini, and the docs refer to bases and components folders as the organising structure of the code.

## Five ways to install the same tooling

Polylith for Python works with Poetry, Hatch, PDM, Rye, Maturin, Pixi, uv and Pantsbuild, and the tooling is distributed as five separate packages rather than one, because each package manager wants the integration in its own shape.

The Poetry plugin, published as poetry-polylith-plugin, adds tooling support to Poetry. The standalone CLI, published as polylith-cli, adds tooling support for several package and dependency managers, with Hatch, PDM, Rye, Maturin, Pixi and uv named. The Hatch build hook, published as hatch-polylith-bricks, adds build specific support, and that one also covers uv, Rye, Pixi and Pantsbuild, using hatchling as the build backend. The PDM build hook for projects, published as pdm-polylith-bricks, adds build specific support for PDM, and the PDM build hook for the workspace, published as pdm-polylith-workspace, makes the virtual environment aware of the way Polylith organises code, which the readme describes as the bases and components folders.

The differences between them are the interesting part, because they show what each manager needs. A plugin or a CLI is added on top of a tool and gives you commands. A build hook is part of the build itself and changes what happens when you build. And the workspace hook is about making the environment match the code layout, which is a PDM specific problem.

The readme also points at example repositories for Poetry, Hatch, PDM, Rye, Pants and uv, and those examples include developer tooling setup such as mypy and the venv. For an adopter, the example for your own package manager is the fastest way to see what a working setup looks like, which matters more here than the prose documentation.

## What the commands actually do

The release titles in the repository are the best short description of the command surface, because each one names a command and a change.

The most recent, stable-116, is a fix to poly diff: a changed file under test/ does not follow the mirrored brick layout. The one before it, stable-115, added a feature to poly test diff: extract related and path based bricks from changed tests. And stable-114 is a fix to poly sync, sorting by type and then alphabetically for Poetry projects.

Three commands therefore stand out. Sync is the one that keeps the workspace consistent, for example after a brick has moved, and the fix in stable-114 shows it ordering the results in a stable way rather than arbitrarily. Diff is about the difference between two states of the codebase, and the fix in stable-116 shows it following the mirrored layout of the test directory, so a change to a test tells you which brick it belongs to. Test diff is the newer one, extracting the bricks related to and path based on the changed tests, which is the feature that answers the question a developer actually has, which of my bricks does this test change affect.

That last one is the most interesting thing in the release history, because it is the tooling turning the architecture into a working tool rather than a directory convention. A monorepo only stays tidy if something keeps it tidy, and the brick oriented diff is that something for the test side of the codebase.

The naming convention for the releases, a stable prefix followed by a number, also tells you how the project versions its own tooling, which is separately from the versioning of the packages that users depend on.

## Libraries as a second, less obvious use case

The readme spends a paragraph on something that is easy to miss, and it is the case where a team has no microservices at all.

Polylith for Python has support for building libraries to be published at PyPI, even if it isn't the main use case, with more detail in the documentation about packaging and deploying a library.

That is worth pausing on, because a library published to PyPI is normally a single distribution, and the Polylith layout splits code into bricks that are assembled into artefacts. The tooling has to reconcile those two shapes, and the fact that a build hook exists for the workspace and another for projects is a hint that the reconciliation is done at build time rather than by asking you to reorganise your code.

The main use case remains services in a monorepo. But the library case explains why the tooling is packaged as build hooks at all. If the only goal were to give you commands to move code around, a CLI would be enough. The build hooks exist because the artefacts have to come out right at packaging time, and that is also where the library case lives.

The examples section lists example repositories for Poetry, Hatch, PDM, Rye, Pants and uv, and describes them as example Python setups of the Polylith Architecture, with examples of sharing code between different kinds of projects, and developer tooling setup such as mypy and the venv. The documentation points to more examples and to production systems.

## Where Polylith for Python is the wrong tool

Four limits, and the first is about what the architecture does not give you.

Polylith is a code organisation approach, not a web framework. There is no request handling, no ORM and no application server in any of these packages, so a service built this way still needs a framework, and choosing that framework is a decision the architecture stays out of. A team that is currently undecided about its web framework will not get help with that here, and a team that wants one framework with batteries included is looking at the wrong repository.

The second is the cost of the monorepo itself. Polylith gives you a way to make a monorepo work, not a reason to have one. The tooling expects a workspace that is kept in order, and the release history shows the sync command being adjusted to produce a stable ordering, which is a small detail that hints at the general point. A team without the discipline to keep a repository tidy will find that the tooling has to compensate for their tidiness, or that the brick boundaries blur until the components are just directories.

The third is the breadth of the packaging. Five packages across Poetry, Hatch and PDM, a standalone CLI, and support for Rye, Maturin, Pixi, uv and Pantsbuild means there is a matrix to keep in step with the tools you use, and a change in one manager's plugin is a change in the shared components underneath all of them.

The fourth is the maturity signal in the manifest itself: the tooling project is at version 0.0.2 in its own pyproject, and the releases are numbered stable-114 to stable-116 rather than carrying semantic versions. The individual packages on PyPI have their own versions, and the download badges in the readme track the Poetry plugin and the CLI separately, which tells you that adoption and release are per package rather than per project.

## Licence, documentation and the state of the project

The licence is MIT, with a LICENSE file at the root of the repository, so the tooling can be used, modified and redistributed with the notice kept. This is not legal advice, and it is worth noting that a permissive licence on the tooling does not change the licences of the code you write with it.

The documentation is the centre of the project, and it lives in its own site at davidvujic.github.io/python-polylith-docs, with installation, setup, usage guides and examples, and the readme links to the specific pages for packaging and deploying a library and for the examples and production systems.

The quality signals in the readme are worth reading. There is a CircleCI pipeline badge, a CodeScene badge for average code health, a SonarCloud quality gate badge, and separate PyPI download statistics for the Poetry plugin and for the CLI. A quality gate on a tool that is itself a build tool is a reasonable thing to require, since the tool's own tests decide whether your monorepo is reported correctly.

On the state of the work, the repository is not archived and the last push was on 2026-10-04, and the three most recent releases are stable-116 on 2026-10-04, stable-115 on 2026-08-07 and stable-114 on 2026-07-27. The repository publishes no GitHub releases, so those tags are the record of what changed and when.

The wider context is documented too, in the form of talks at PyData Amsterdam 2025 and FOSDEM 2025, a Talk Python To Me episode on monorepos in Python, and a set of articles by the author, one of them titled The last Python Architecture you will ever need. For a team deciding whether this architecture fits, that material is a faster way to understand the author's position than the package listings are.

## Conclusion

python-polylith is the right tool for a Python team that already runs several services in one repository and wants to share code between them while keeping each service independently deployable, and for a team that has outgrown a single application but does not want a multi repository dependency mess. It is the wrong tool for a single service, for a team without the discipline to keep a monorepo tidy, and for anyone who needs the framework support that Polylith deliberately leaves out. Before adopting, look at the example repositories for the package manager you use, and check the release notes, because the tooling is versioned separately for each package and the command set is still moving.

## FAQ

### What is python-polylith?

It is tooling support for the Polylith Architecture in Python, an architecture originally built for Clojure that applies a components first approach in a monorepo. The main use case is supporting one or more microservices or apps in a monorepo and sharing code between them, and it also supports building libraries published to PyPI.

### How is the Polylith tooling for Python packaged?

As five packages: a Poetry plugin called poetry-polylith-plugin, a standalone CLI called polylith-cli, a Hatch build hook called hatch-polylith-bricks, and two PDM hooks called pdm-polylith-bricks for projects and pdm-polylith-workspace for the workspace. The CLI and the Hatch hook also cover Hatch, PDM, Rye, Maturin, Pixi, uv and Pantsbuild.

### What do the poly sync and poly diff commands do?

Sync keeps the workspace consistent, for example after a brick has moved, and sorts by type and then alphabetically for Poetry projects. Diff reports the difference between two states of the codebase, and a recent fix made it follow the mirrored brick layout for changed files under test. A newer command, poly test diff, extracts the related and path based bricks from changed tests.

### Is Polylith for Python a web framework?

No. It is a code organisation approach with tooling for it, and it does not include request handling, an ORM or an application server. A service built this way still needs a web framework, and the tooling's job is to organise and package the code rather than to serve it.

## Sources

- [DavidVujic/python-polylith on GitHub](https://github.com/DavidVujic/python-polylith)
- [License: MIT](https://github.com/DavidVujic/python-polylith/blob/main/LICENSE)
- [Project website](https://davidvujic.github.io/python-polylith-docs/)
- [README](https://github.com/DavidVujic/python-polylith/blob/main/README.md)
- [Releases](https://github.com/DavidVujic/python-polylith/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/davidvujic-python-polylith
