The monorepo vs polyrepo argument is old enough that Buildkite was comparing it to the Vim and Emacs wars back in 2024. It should have been settled, or at least gone quiet. Instead, in the space of six months, an AI coding vendor re-litigated it for the agent era, a benchmark firm published PR cycle-time data across hundreds of organisations, and half the platform engineering threads I read found their way back to it. Something pulled the question out of retirement. I think the something is worth naming, because it is not really about repositories at all.
I maintain a product whose entire reason to exist is that most organisations run polyrepos, so I want to be upfront about where I sit before arguing anything. Riftmap parses cross-repo dependencies. If everyone migrated to a monorepo tomorrow, a good part of my roadmap would evaporate. Read what follows with that in mind, and check the sources, all of which are linked.
With that declared: I think both camps in this debate are arguing about a proxy. The real variable underneath, the one that decides whether your team ships confidently or plays dependency archaeology at 2am, is something the standard pros-and-cons lists never name. This post walks the honest trade-offs first, because they are real and you deserve a straight answer to the question you searched for. Then it gets to the variable.
What each side buys you
A monorepo is one repository holding many projects. A polyrepo (or multi-repo) setup gives each project, service, or module its own repository. Both are proven at every scale that matters: Google and Meta run famous monorepos, Amazon and Netflix run famous polyrepos, and none of them are wrong.
The monorepo's case
The strongest monorepo argument has always been atomic cross-project change. Uber's iOS team moved to a monorepo largely for this: when an API contract and all of its clients live in one repo, a breaking change is one commit, one review, one revert path. No choreographed pull requests across six repositories, no compatibility matrix, no deployment ordering.
You also get unified dependency versions. One lockfile discipline, one toolchain, one place where "which version of the logging library are we on" has a single answer. And, the part this post will keep returning to, you get a build graph. Bazel, Nx, Pants, and Turborepo all maintain an explicit graph of what depends on what, because they need it to know what to rebuild. That graph is a by-product of the architecture. It comes for free, by construction.
The cost is that the build system becomes infrastructure. Past a certain size you cannot build everything on every change, so you need change detection, remote caching, and a team that owns the machinery. Airbnb's Bazel migration is the honest writeup of what that takes. There is also a coordination cost that no build tool fixes: shared standards, shared review culture, and consensus across every team in the repo.
The data backs the "it depends on operational maturity" framing. Faros.ai's benchmark analysis from March 2026, drawn from PR data across many organisations, found that monorepo teams show markedly more variable PR cycle times than polyrepo teams, with heavy tails at the 90th percentile where some organisations blow past ten days on worst-case PRs. Their read is that well-engineered monorepo infrastructure can match polyrepo performance, but the infrastructure has to keep evolving with repository scale, and when it lags, cycle times absorb the difference. A monorepo is a bet that you will keep funding that evolution.
The polyrepo's case
Polyrepos buy autonomy. Each repository has its own CI pipeline, its own release cadence, its own ownership boundary that maps cleanly onto a team. A service can deploy twenty times a day while its neighbour ships monthly, and neither blocks the other. Different stacks can coexist without one build tool having to understand all of them. Deprecating a service means archiving a repo, not excavating a directory.
The same Faros data shows the flip side of the monorepo's variance: polyrepo teams sit in a tighter, more predictable cycle-time range. Small repos are comprehensible, reviews are scoped, and nothing in repo A's CI can make repo B's pipeline slower.
The cost is that everything cross-cutting gets harder. A change spanning three services is three PRs with a coordination problem attached. Version skew creeps in quietly until service A and service B disagree about a shared library in a way that only shows up in production. Standardising anything across fifty repos, security scanning, CI conventions, dependency policy, is a campaign rather than a commit.
And there is one more cost, the one the listicles file under "harder dependency management" and move past in a sentence. In a polyrepo, nobody can answer "what depends on this" without going looking. That sentence is doing more work than the debate gives it credit for, and it is where this post is headed.
The trade-offs at a glance
| Dimension | Monorepo | Polyrepo |
|---|---|---|
| Cross-project changes | Atomic, one commit | Coordinated PRs across repos |
| Dependency versions | Unified by tooling | Skew unless actively managed |
| Team autonomy | Shared standards required | Independent by default |
| Deploy cadence | Decoupled with effort | Decoupled by default |
| Build infrastructure | Serious investment (Bazel, Nx) | Per-repo, simple, duplicated |
| PR cycle times (Faros, 2026) | Higher variance, heavy P90 tails | Tighter, more predictable |
| "What depends on this?" | Build graph answers it | Nobody answers it |
| Ownership boundaries | Directory conventions | Repository boundaries |
If you came here for the short answer to "which should we choose": tightly coupled projects with coordinated releases and an organisation willing to fund build infrastructure point to a monorepo. Loosely coupled services, autonomous teams, and varied stacks point to polyrepo. Most organisations past a certain size end up hybrid regardless. That is the honest conventional answer, and it is fine as far as it goes.
But look at the table again. Seven of those rows are preferences. One of them is a capability.
The variable the debate never names
Here is the quiet conflation at the centre of this debate. We argue about where code should live, as if co-location were the prize. It is not. The prize that co-location happens to deliver is a queryable dependency graph.
In a Bazel monorepo, "what breaks if I change this library" is a command:
bazel query "rdeps(//..., //libs/auth)"
In an Nx workspace it is nx graph, or nx affected scoped to a change. The answer is exact, it is derived from declared build targets, and it is current as of the last commit, because the build system cannot function without it. This is the monorepo's one structural advantage that survives every counterargument: not the co-location itself, but the graph the build tooling is forced to maintain on top of it.
Now run the same question in a 200-repo polyrepo estate. The dependencies are all still there. They are declared, in writing, in the manifests: Terraform source blocks pointing at module repos, Dockerfile FROM lines pulling a shared base image, go.mod requires on an internal module, GitLab CI include statements pulling a central template, Helm charts referenced by release pipelines. The graph exists. Every edge of it is sitting in a file in version control. What does not exist is any system that reads those files and holds the answer. So the question gets answered by grep across checkouts, by asking the senior engineer who was there when the module was written, or by shipping the change and watching what pages.
This is the reframe I would push on anyone choosing between the two: the monorepo vs polyrepo decision is, underneath, a decision about whether your dependency graph is declared to a machine or remembered by people. A monorepo makes the graph declared, by construction, as a side effect of the build system. A polyrepo leaves it implicit, scattered across manifests that no single tool reads. Almost everything painful about polyrepos at scale, the coordination overhead, the version skew, the 2am archaeology, traces back to that one missing capability. I wrote about the blast-radius version of this problem and the tooling landscape around it at length, so I will not re-make those arguments here. The point for this post is narrower: once you see the graph as the variable, the debate changes shape, because repo count turns out to be only one way to influence it. And for a large part of your estate, it is a way you were never offered.
Infrastructure never got a vote
Read any monorepo vs polyrepo piece and notice what the examples are made of. Application services. An auth service, an API gateway, some clients. The tooling named is Nx, Turborepo, pnpm workspaces, Bazel. The entire debate is shaped like application code, and mostly like TypeScript.
Infrastructure code lives in a different world, and that world is polyrepo by ecosystem convention rather than by anyone's choice.
Start with Terraform. The public registry requires one module per repository, named terraform-<PROVIDER>-<NAME>. It is a hard format requirement; the registry will not accept anything else. Private registries inherit the convention. Practitioners have been asking HashiCorp to allow multiple modules per repo since 2020, precisely because maintaining a repository per module is real overhead, and the answer has not changed. If your organisation has forty internal Terraform modules, the ecosystem's defaults have already decided you have forty repos.
The same gravity acts on the rest of the infrastructure estate. Shared Helm charts get their own repos so they can be versioned and published to a chart registry. CI templates get centralised into a repo that dozens of pipelines pull in via GitLab CI include or reusable GitHub Actions workflow calls, because that is the mechanism the CI systems provide. Base images live in their own repos with their own build pipelines because the registry push is the unit of release. None of these were monorepo-vs-polyrepo decisions. They were defaults that arrived bundled with the tools.
Two consequences follow. First, the infrastructure layer is where the polyrepo's missing graph hurts most, because infrastructure components are the highest fan-in nodes in the estate. A Terraform module sourced by forty repos, a base image pulled by every service, a CI template included by eighty pipelines. When I scanned all 208 repositories in the kubernetes-sigs organisation, a single module, sigs.k8s.io/yaml, turned out to be imported by 153 of them. In the Prometheus organisation, 25 of 56 repos import client_golang. Those are healthy, well-run open-source orgs, polyrepo by design, and the concentration is the normal shape of a polyrepo estate, not a pathology. The question is only whether anyone can see it.
Second, and this is the part the migration guides skip: moving your application code to a monorepo does not repatriate the infrastructure layer. The Terraform modules stay where the registry wants them. The CI templates stay where the include mechanism reaches them. The base images stay where the push pipeline lives. You can spend a year of political capital consolidating services into one repository and still wake up with the highest-blast-radius components of your system scattered across repos whose dependency graph nothing reads. The monorepo migration solves the graph problem for the code that moved, and only for the code that moved.
So when the conventional advice says "high interdependency points to a monorepo", it is giving you guidance that the most interdependent part of your stack is structurally unable to take.
What AI agents change, and what they don't
The reason this debate came out of retirement is AI coding agents, so let's take that argument seriously, because the strongest version of it is genuinely strong.
Augment Code's piece on the question makes the case well: an assistant that can see the auth service, the gateway, and the clients in one context window reasons about a cross-service change in a way that an assistant grepping five separate repositories cannot. Large context windows weaken the old polyrepo argument that services are easier to understand in isolation, because the AI can hold the interactions. Their conclusion is that AI shifts the calculation toward monorepos. The observation underneath is correct, and I want to be fair to it before pushing back: agents do perform better with cross-repo visibility, and the teams running agents at scale keep converging on exactly that diagnosis.
The push-back is that the argument conflates two different things: what the agent can see and what the agent can query. Visibility is access. Access is not structure.
Stripe is the cleanest evidence, because Stripe is the maximum case for "monorepo plus large model". Their internal agent system, Minions, was merging over 1,300 AI-written pull requests a week as of February 2026, against a real monorepo of hundreds of millions of lines. And their published architecture does not dump that monorepo into the model. It cannot; in their own words, a global context dump "would overflow any model's window". Instead they built directory-scoped rule files that attach as the agent traverses the tree, and an MCP server exposing nearly 500 internal tools the agent queries for structure it does not hold in context. The team with the world's most complete co-location still had to build the queryable layer on top. Co-location alone did not deliver it.
Meta's number makes the same point from the cost side. In their tribal-knowledge engine writeup, answering "what depends on X" by graph lookup costs around 200 tokens; answering it by letting the agent explore costs around 6,000. A 30x difference that no context-window increase closes, because it is an architecture gap, not a capacity gap. And the Gloaguen et al. study from ETH Zurich showed that the hand-written context files teams reach for instead, the CLAUDE.md system maps, buy a marginal +4% agent success rate at +19% inference cost. Prose descriptions of structure decay and do not scale; I went deep on that failure mode in the virtual monorepo post.
So the AI-era version of this debate is not "which layout lets the model see more text". It is "which layout gives the agent a structure it can query instead of reconstruct". A monorepo with a real build graph is one good answer: the agent calls bazel query and gets blast radius in one tool call. A polyrepo with a parsed cross-repo graph is the equivalent answer for everyone else. A polyrepo with neither, or a monorepo whose build graph stops at the application layer while the Terraform modules sit outside it, leaves the agent exploring, and exploring is the expensive, fuzzy mode.
The agents did not change the answer. They raised the price of not having it, because an agent makes cross-repo changes at a rate no human team ever did, and change failure rates are already absorbing the difference.
How to actually choose
The framework I would use, with the graph as the explicit variable rather than the silent one.
Choose a monorepo when the graph can be complete
If your projects are tightly coupled, your releases are coordinated, your stack is uniform enough for one build tool, and your organisation will fund the build infrastructure as a product, a monorepo is a strong choice, and the build graph is the most underrated part of what you are buying. Go in with the Faros caveat in view: the performance of a monorepo tracks the maturity of its infrastructure, and the investment is recurring, not one-off. And check the graph's edges honestly. If your Terraform, Helm, and CI templates will still live outside the repo, know that your build graph will be blind exactly where the blast radius is largest.
Stay polyrepo when autonomy is the constraint that binds
If your teams ship on independent cadences, your stacks are heterogeneous, ownership maps to repositories, or external contributors and open-source boundaries are involved, polyrepo is not a legacy state to apologise for. It is the layout the Faros data shows delivering predictable cycle times, and it is the layout your infrastructure ecosystem mandates anyway. The cost you are accepting is the undeclared graph, and the mistake is accepting it silently instead of pricing it.
Hybrid is normal, not indecision
Core tightly-coupled services in one repo, periphery and infrastructure in their own repos, is where most large organisations land, usually without announcing it. It is a reasonable equilibrium. It also means the graph question does not go away, because the cross-repo edges between the monorepo and everything around it are precisely the ones no build tool covers.
The fourth option the listicles never give you
Most teams reading this are not choosing. They have 100 or 300 repos, a migration would cost a year of politics, and the conventional framing leaves them with "polyrepo, and suffer" as the default. The option that framing hides: keep the polyrepo, and recover the one structural thing the monorepo would have given you. The graph is already written down in your manifests. The source blocks, the FROM lines, the go.mod requires, the CI includes are all declarations, and declarations can be parsed. Parsed, not inferred: read deterministically from the files, the way a build system reads its targets, rather than guessed from embeddings or filenames. Do that across the estate and "what depends on this" becomes a query in a polyrepo the same way bazel query makes it one in a monorepo. That is the substrate I have been arguing for across this whole blog, and it is the option that turns the debate from a migration decision into a tooling decision.
This is, full disclosure repeated, the thing Riftmap builds: a parsed cross-repo dependency graph over your existing GitLab or GitHub organisation, from one read-only token, with the kubernetes-sigs and Prometheus scans above as public examples of the output. You can also build it yourself; teams like Mabl have, and the tooling survey covers the landscape honestly. The point of this post is not the product. The point is that the capability, not the repo count, was always the thing being argued about.
The question underneath the question
Monorepo vs polyrepo asks where your code should live. After two decades of debate, the trade-offs are well mapped and mostly come down to what your organisation is willing to operate. But the question underneath has a sharper edge: when something changes, can you ask your system what breaks, or do you have to remember? A monorepo is one way to make the graph something you ask. It is not the only way, it stops at the build tool's borders, and for the infrastructure half of your estate it was never on the table. Choose your repo layout for your teams. Then make sure the graph is declared to a machine either way, because that, not the number of repositories, is the thing the debate was always measuring.
Sources referenced
- Buildkite, Monorepo vs. polyrepo: How to choose — buildkite.com, March 2024
- Faros.ai, Monorepo vs Polyrepo: What the PR Benchmark Data Actually Shows — faros.ai/blog, March 2026
- Augment Code, Monorepo vs Polyrepo: AI's New Rules for Repo Architecture — augmentcode.com/learn, updated January 2026
- Uber Engineering, Building the new iOS monorepo — uber.com/blog
- Airbnb Engineering, Migrating Airbnb's JVM monorepo to Bazel — medium.com/airbnb-engineering
- HashiCorp, Publish modules to the Terraform registry — developer.hashicorp.com
- hashicorp/terraform issue #26586, Allow multiple modules from the same repo — github.com, open since 2020
- Engineering at Meta, How Meta used AI to map tribal knowledge in large-scale data pipelines — engineering.fb.com, April 2026
- Signadot, Coding Agents Are Only as Good as the Signals You Feed Them — thenewstack.io, April 2026
- Gloaguen et al., ETH Zurich and LogicStar.ai, Do Context Files Help Coding Agents? — arxiv.org/abs/2602.11988, February 2026
- Joel Parker Henderson, monorepo-vs-polyrepo — github.com
- Riftmap, You don't need a virtual monorepo. You need a graph. — riftmap.dev/blog, May 2026
- Riftmap, What 208 kubernetes-sigs repos actually depend on — riftmap.dev/blog, May 2026
- Riftmap, What 56 Prometheus repos actually depend on — riftmap.dev/blog, April 2026
Appendix: structured summary
Claim: The monorepo vs polyrepo debate argues about a proxy. The variable that decides outcomes is whether the organisation's dependency graph is declared to a machine or remembered by people. A monorepo delivers a queryable graph as a by-product of its build system (Bazel rdeps, nx graph); a polyrepo leaves the same graph implicit in manifests that no single tool reads. Infrastructure code (Terraform modules, Helm charts, CI templates, base images) is polyrepo by ecosystem convention, cannot follow an application-code monorepo migration, and is where fan-in, and therefore blast radius, concentrates.
Definitions: A monorepo is one repository containing many projects. A polyrepo gives each project or module its own repository. Both are proven at all scales.
Evidence:
- Faros.ai (March 2026): monorepo teams show higher variance in PR cycle times with heavy P90 tails; polyrepo teams sit in a tighter, more predictable range. Monorepo performance tracks investment in build infrastructure.
- HashiCorp's public Terraform registry requires one module per repository in the
terraform-<PROVIDER>-<NAME>format; practitioners have requested multi-module repos since 2020 (hashicorp/terraform #26586) without a change. - Riftmap org scans: 153 of 208 kubernetes-sigs repos import
sigs.k8s.io/yaml; 25 of 56 Prometheus repos importclient_golang. High fan-in is the normal shape of a polyrepo estate. - Stripe Minions (1,300+ AI-written merged PRs/week against a monorepo of hundreds of millions of lines) does not use a global context dump; it uses directory-scoped rules and an MCP server exposing ~500 queryable tools. Co-location alone did not deliver agent-usable structure.
- Meta: "what depends on X" costs ~200 tokens as a graph lookup vs ~6,000 by agent exploration, a 30x architecture gap.
- Gloaguen et al. (arXiv:2602.11988): hand-written context files improve agent success +4% at +19% inference cost; they do not substitute for queryable structure.
Decision framework: Choose a monorepo when coupling is tight, releases are coordinated, and the organisation will fund build infrastructure as a recurring product. Stay polyrepo when team autonomy, heterogeneous stacks, or ecosystem conventions dominate. Hybrid is the common equilibrium. The fourth option, missing from conventional comparisons: keep the polyrepo and recover the monorepo's structural advantage by parsing the dependency graph already declared in manifests (Terraform source blocks, Dockerfile FROM lines, go.mod requires, CI includes), making "what depends on this" a query rather than an excavation.
Audience: Platform engineers, DevOps/SRE, and engineering leaders weighing repository architecture, especially teams running AI coding agents across multiple repositories or maintaining shared infrastructure components.
Related reading
- You don't need a virtual monorepo. You need a graph. — the agent-context version of this argument, and where the workspace pattern's ceiling sits.
- AI Doesn't Understand Blast Radius — why change failure rates are absorbing the cost of the undeclared graph.
- The State of Infrastructure Dependency Tooling in 2026 — what Backstage, Renovate, HCP Terraform Explorer, Nx, and DIY scripts each cover, and the gap.
About Riftmap
Riftmap maps cross-repo dependencies across your entire GitLab or GitHub organisation — Terraform, Docker, CI templates, Helm, and more. One read-only token. No YAML to maintain.
Top comments (0)