Monolithic vs Polyrepo Pipelines
One pipeline or many.
Monolithic pipeline pattern
Monolithic pipelines are simple but break at scale. One pipeline runs every test, every check, and every build on every commit; the simplicity that works at 5 services collapses at 50.
- Single pipeline for the whole repo. Every test, check, and build per commit; standard starting pattern that suits small teams.
- Simple to understand. One pipeline for new engineers to learn; onboarding stays cheap while the team is small.
- Brutal at scale. Cannot run every test on every commit past about 1,000 services; CI runtime grows with repo size, not change size.
- Works to about 20 services. Switch patterns past this threshold; pretending monolithic still works produces 30-minute CI runs that block teams.
Polyrepo pipelines
Polyrepo gives each service its own repository and its own pipeline. Scales naturally because each pipeline stays small; trades tooling drift across repos for parallelism.
- Per-service pipeline. Independent CI per repo; independent code, independent build, independent failure modes.
- Scales naturally. Parallel pipeline-count growth per org; each individual pipeline stays fast as the team grows.
- Cost: tooling drift. Duplicated config across repos, harder cross-service refactors; real ongoing tax that compounds with repo count.
- Shared CI template per org. Central tooling investment catches drift; without it, every repo's CI eventually diverges.
Selective pipelines (the modern monorepo pattern)
Selective pipelines run only the affected slice of tests on each commit. Bazel, Nx, Turborepo, and Pants all compute the affected set from the build graph; the pattern combines monorepo simplicity with polyrepo CI cost.
- Only run affected tests. Change-aware test selection per commit; Bazel, Nx, Turborepo, Pants all compute the affected set from dependencies.
- Best of both worlds. Monorepo simplicity plus scaled CI cost; the modern pattern at meaningful repo size.
- Requires accurate dependency tracking. Build graph correctness per repo; without it, the affected set is wrong and tests get silently skipped.
- Quarterly dependency-graph audit. Build-graph correctness check per quarter catches silent test-skipping that produces false confidence.
Scaling each pattern
Each pattern scales differently. Monolithic parallelises within itself but cannot escape the all-tests-on-every-commit ceiling; polyrepo shares templates to stay coherent; selective depends on graph correctness as the load-bearing assumption.
- Monolithic: parallelise within. Matrix builds and sharded tests buy headroom; do not escape the ceiling, just delay hitting it.
- Polyrepo: shared templates. Central CI tooling team per org keeps pipelines in sync; without it, drift produces per-team variance that compounds.
- Selective: graph correctness. Dependency-graph investment per repo; the whole pattern depends on it being accurate.
- Named scaling owner per pattern. Responsible CI team per org catches degrading CI performance before it slows the whole org.
How to pick
The pick is shape-driven. Single small repo with under 20 services goes monolithic; multiple independent repos go polyrepo; large monorepo goes selective. Picking against the shape produces friction every day.
- Single repo, under 20 services. Monolithic pipeline pick; simplest pattern that works at this scale and onboarding stays cheap.
- Multiple repos. Polyrepo with shared templates; the standard pattern when independent services live in separate repos.
- Monorepo above 20 services. Selective pipelines (Bazel, Nx, Pants); scales properly past the monolithic ceiling.
- Documented driver per decision. Named "why this pattern" note catches "we just kept what we had" defaults that nobody chose.