Quick take
If your code changes together, put it together. If your teams release independently, keep them separate. Everything else is tooling cost and organizational preference. Stop arguing about it on Twitter.
This debate generates more heat than it deserves. I’ve worked in both models – a monorepo at Decloud where three engineers touched everything, and polyrepos at larger companies where dozens of teams needed autonomy. Both worked. Both had pain points. The difference was never the repo structure itself. It was whether the structure matched how the code actually changed.
The Real Question
Forget “monorepo vs. polyrepo” as an identity choice. Ask these questions instead:
- How often do changes span multiple services or libraries?
- How independent are your team release cycles?
- How much build infrastructure are you willing to own?
That’s basically it. The answers determine the tradeoff surface.
The Tradeoff Table
| Dimension | Monorepo | Polyrepo |
|---|---|---|
| Cross-cutting changes | Single commit, single review | Multiple PRs, version coordination, prayer |
| Build complexity | Needs smart builds, caching, selective testing | Standard CI per repo, but dependency sync is your problem |
| Team autonomy | Lower – shared standards, shared tooling | Higher – own stack, own cadence, own mistakes |
| Shared code | Easy to update, hard to ignore | Easy to fork, hard to keep in sync |
| Onboarding | Everything is discoverable in one place | Context is scattered across repos, wikis, tribal knowledge |
| Access control | Coarser – everyone sees everything (usually) | Fine-grained per repo |
| Release coordination | Natural – everything moves together | Requires explicit compatibility contracts |
| Failure blast radius | A bad merge can block everyone | Contained per repo |
Neither column is universally better. It depends on your situation.
When Monorepo Wins
Monorepo shines when coupling is real, not aspirational. If your backend API change requires a frontend update and a shared library bump, doing that across three repos with three PRs and a release dance is painful. A monorepo makes it one commit with one review.
It also works when you want consistency. Shared linting, shared CI, shared tooling – all easier when there’s one source of truth. At one company with fifteen microservices, we moved to a monorepo and immediately found three services using different logging libraries for no reason. Consolidation happened naturally once the code was visible.
The cost is real though. You need smart builds. Running all tests for every change in a repo with fifty services isn’t viable. Tools like Bazel, Nx, or Turborepo exist for this reason, but they aren’t free to set up or maintain. The repository itself becomes infrastructure, and someone has to own it.
When Polyrepo Wins
Polyrepo wins when teams are genuinely independent. If your payments team and your notifications team share an API contract but otherwise never touch each other’s code, separate repos give them freedom to move at their own pace. Different languages, different deploy schedules, different testing strategies – all fine.
Permissions are simpler too. Contractors working on one service don’t need to see the entire codebase. Compliance teams are happier when access boundaries are clean.
The cost is coordination. Cross-repo changes require versioning, compatibility planning, and discipline. Shared code gets forked, diverges, and becomes a source of subtle bugs. I’ve seen organizations with thirty repos where “shared utilities” existed in five slightly different versions across teams, each with its own bugs.
The Hybrid Reality
Most organizations I’ve worked with end up somewhere in the middle. A few domain-aligned monorepos – one for the core platform, one for data pipelines, one for customer-facing apps – with polyrepo isolation between domains. This is fine as long as it’s deliberate.
The danger is the accidental hybrid: some code is in the monorepo because someone put it there, some is in separate repos because someone else preferred that, and nobody wrote down why. That’s how you get the worst of both worlds.
Decision Checklist
Answer honestly:
- Cross-service changes happen weekly or more? Lean monorepo.
- Teams need independent release schedules? Lean polyrepo.
- You have (or will build) dedicated build tooling capacity? Monorepo is feasible.
- Permissions and isolation are a hard requirement? Polyrepo is simpler.
- Shared code is a core part of delivery speed? Monorepo makes it visible and maintainable.
If you’re split 3-2 either way, you’re probably fine with either model. Pick one and commit to owning the tradeoffs.
Migration Is Possible but Expensive
I’ve helped teams move in both directions. It’s never a weekend project. You need a clear boundary map, a dependency inventory, and a staged migration plan. Treat it like a product initiative with dedicated ownership, not a “we’ll do it gradually” background task. Gradual migrations without ownership die quietly and leave you in the worst-of-both-worlds hybrid.
What matters
The repo structure is a tool, not an identity. Match it to how your code changes, how your teams work, and what infrastructure you can sustain. The worst outcome isn’t picking the wrong model – it’s having no deliberate choice at all and ending up with an accidental mess that nobody owns.