How to choose between a monorepo and multiple repos

Every team that starts a second service asks the same question: does this new code go in the same repository as the first one, or does it get its own? The question sounds like a style preference. It is not. It decides how your team reviews code, how it deploys, and how fast a change can move from one part of the system to another for the rest of the project's life.
We have watched teams pick a repository structure because a conference talk from a big company recommended it, then spend a year working around the mismatch between that structure and their actual size. The right call is not about which pattern is more modern. It is about three measurable things: how many people are touching the code, how tightly your services have to deploy together, and how often code needs to move between them. A fourth factor has become real in the last two years: what an AI coding agent can and cannot see across a repository boundary.
Start with team size, not architecture
The instinct is to pick a repository shape based on how the system is designed: microservices go in separate repos, a single application goes in one repo. That instinct is wrong on its own, because a repository is a boundary for people, not for services.
A team of three to eight engineers working on a product with several connected services almost always moves faster with one repository. Everyone can see every change. A pull request that touches the API and the worker that processes its output shows up as one diff, reviewed by one person, merged in one commit. Nobody has to coordinate two separate release timelines to ship one feature.
That changes as headcount grows and ownership splits. Once a team owns a slice of the system on its own, with its own on-call rotation and its own decision on when to release, a shared repository starts working against that team instead of for it. Every unrelated change in another team's folder still shows up in their commit history, still triggers their CI, and can still block their merge queue if it breaks something they did not touch. At that point, separate repositories give each team a clean boundary that matches how the org actually makes decisions.
The rule of thumb: repository structure should track your reporting structure and release ownership, not your service diagram. A single team owning five services should probably keep them in one repository. Five teams each owning one service should probably not.
Look at deploy coupling before you look at code sharing
The second input is how tightly your services have to deploy in step with each other. This is the factor teams skip, and it is the one that causes the most pain when it is wrong.
If a change to your API almost always requires a matching change to your frontend, and the two have to ship together to avoid breaking each other, that is tight deploy coupling. A monorepo makes tight coupling easy to manage: one commit, one CI run, one deploy that moves both pieces at the same time. Splitting tightly coupled services into separate repositories does not remove the coupling. It just makes the coupling invisible until a mismatched deploy breaks something in production, because now two repositories have to be updated and released in the right order by two different people.
If your services genuinely deploy on independent schedules, separate repositories remove noise instead of adding risk. A billing service that changes once a quarter should not sit in the same repository, the same CI pipeline, and the same access list as a customer-facing app that ships several times a week. Bundling them together means the billing team's CI runs on every unrelated app change, and the app team's pull requests show billing history they have no reason to read.
A useful test: pull up your last twenty production deploys. If most of them touched exactly one service, your services are already loosely coupled, and separate repositories will not cost you anything. If most of them touched two or more services at once, they are tightly coupled today whether or not your repository structure says so, and a monorepo will save you the coordination tax.
Shared code tells you which way to lean
The third input is how often code actually moves between services: a validation function, a type definition, a client library, a design system component. This is where a monorepo earns its keep or turns into unnecessary weight.
When shared code changes often and every service needs the new version immediately, a monorepo removes an entire category of coordination problem. There is no version to bump, no package to publish, no service silently running last month's copy of a shared function because nobody updated its dependency. The change lands in one commit and every consumer in the repository sees it in the same pull request.
When shared code is small and changes rarely, this benefit shrinks to almost nothing, and the cost of a monorepo (a larger checkout, slower search, more noise in the commit history) stops paying for itself. In that case a small internal package, versioned and published normally, does the job with less overhead.
Google is the standard reference point for a monorepo working at real scale, and the actual numbers back the argument that structure and deploy strategy are separate decisions: Google's own engineers reported in Communications of the ACM that its monorepo holds roughly two billion lines of code across nine million source files, used by more than 25,000 developers, all in one repository. Google does not deploy that repository as one binary. It builds and ships thousands of independent services out of it, using build tooling that tracks precisely which files a change touched so only the affected pieces rebuild and retest. The repository structure and the deploy strategy are two different decisions, and Google's scale only works because of custom tooling most teams have no reason to build. The lesson is not "copy the shape." It is "the shape and the release process solve different problems, and you need a real answer to both."
How AI coding agents change the calculus
The newest input in this decision did not exist five years ago. An AI coding agent that writes code across your repository has a working memory limit, called a context window: the amount of text it can hold and reason about in one pass. When a change spans several services, a bigger context window lets the agent read all the related code, understand how the pieces connect, and make the change consistently across every file, instead of drafting each service's edit in isolation and hoping the pieces still fit together when a person stitches them back.
That limit used to be a real constraint. It has grown fast: Anthropic's own announcement states that Claude Sonnet 4 supports up to 1 million tokens of context, a fivefold jump from its prior 200,000-token limit, enough in the company's words to hold "over 75,000 lines of code" in a single request. A change that touches an API contract, the client that calls it, and the shared type definition between them now fits inside one working session for the agent, in one repository, where it can see all three files at once.
That capability matters most when those three files live in one place. A monorepo lets an agent open the API, the client, and the shared type in the same pass, make a change that keeps all three in sync, and submit it as one reviewable pull request. In a polyrepo setup, the same change requires the agent, or the engineer directing it, to work across separate checkouts, separate pull requests, and separate CI pipelines, then manually verify the pieces still agree with each other after each one merges on its own schedule. The agent does not remove the coordination problem in that setup. It just does the typing faster while the coordination problem stays exactly as manual as it always was.
This does not mean every team should collapse into one repository because an agent can handle the resulting size. It means the crossover point, the team size or deploy coupling level at which a monorepo starts paying for itself, has moved. Cross-service refactors that used to need a senior engineer coordinating three pull requests by hand can now be one agent session against one repository, provided the code the change touches actually lives inside the context window. A large enough monorepo will still exceed even a 1-million-token window; the benefit is real but not limitless.
A short decision rule
Put the four inputs together and the choice gets simpler than most teams expect.
Pick one repository when a small team owns several tightly coupled services, when most deploys already touch more than one of them, and when shared code changes often enough that version drift between services is a real risk. This is also the setting where an AI coding agent gets the most benefit from a monorepo, because a cross-service change fits in one context window and lands as one reviewable change.
Pick separate repositories when ownership has split across teams with independent release schedules, when most deploys already touch exactly one service, and when the code shared between them is small and stable. Splitting here removes noise without removing any coordination you actually needed.
Neither structure is a fixed decision. Plenty of systems start as one repository while the team is small and the services are tightly coupled, then split specific pieces out once a team, a release schedule, or a security boundary genuinely diverges. The mistake is not picking the wrong one on day one. It is picking a structure based on what a well-known company does at a completely different scale, then keeping it long after your own team size, deploy pattern, or agent-assisted workflow has moved past the reasons that structure made sense.
A repository is a boundary you draw around people and deploys, and it should move when they do.
Sources
- Why Google Stores Billions of Lines of Code in a Single Repository, Communications of the ACM: supports the figures on Google's monorepo scale (roughly two billion lines of code, nine million source files, more than 25,000 developers) and the point that repository structure and deploy strategy are separate decisions.
- 1M token context window, Claude blog (Anthropic): supports the figure on Claude Sonnet 4's context window (1 million tokens, a fivefold increase from 200,000) and the stated capacity of over 75,000 lines of code in a single request.


