Monorepos, Microservices, and the Architecture Pendulum
2026-04-03
2026-04-03
Around 2014-2017, microservices were the only architecture anyone wanted to talk about. Netflix, Spotify, and Amazon were the poster children, and the message the industry absorbed was clear: monoliths are legacy, microservices are modern. Conference talks, blog posts, and hiring trends all reinforced that framing. If you were building a monolith, you were doing it wrong.
Then reality caught up.
Teams discovered the hidden costs of distributed systems. Distributed tracing became a nightmare, network latency between services added up, data consistency across service boundaries was painful, and the operational overhead of managing dozens of repos with independent CI pipelines burned through engineering time. People like Kelsey Hightower and even Sam Newman (who wrote the book on microservices) started cautioning against premature decomposition. Martin Fowler's team put it simply: don't start with microservices, earn them.
The pattern became common enough to get its own narrative: monolith to microservices and back to monolith. In 2023, Amazon Prime Video published a case study where they moved back from microservices to a monolithic architecture for a video monitoring workload and cut costs by 90%. That made waves precisely because it came from Amazon itself.
The industry didn't swing all the way back though. The current consensus is more nuanced: start with a well-structured modular monolith, extract services only when you have a clear operational or scaling reason, and keep your architecture decisions tied to your actual problems rather than to conference hype.
One source of confusion is the word "monorepo" getting treated as a synonym for monolith. They are fundamentally different concepts.
A monolith is an architectural and deployment pattern. One deployable unit, one runtime, tightly coupled code.
A monorepo is a source code management strategy. One repository containing multiple projects, libraries, or even independent services.
These are orthogonal decisions. You can mix and match them freely, and all four combinations are valid: one repo with one deployable unit is the classic monolith setup most small teams start with. One repo with many deployable services is the Google-style monorepo with microservices. Many repos with many services is the "pure" microservices approach that was popular around 2015. And many repos with a monolithic deployment is possible too, though it is rare and usually painful.
The confusion happens because "mono-" appears in both words and because the back-to-simplicity energy applies to both dimensions at the same time. Teams burned by 50 repos with 50 CI pipelines are consolidating into monorepos while teams burned by distributed complexity are consolidating toward monolithic architectures. The motivations overlap (reducing accidental complexity) but the decisions are independent.
Here is where things get interesting. AI coding agents are fundamentally context-dependent, and monorepos maximize the context surface available without friction.
When an agent like Claude Code needs to implement a feature that touches both your API and your frontend, having both in the same repo means it can trace the contract end-to-end: the API endpoint definition, the shared types, the frontend call, the error handling. It does not need you to manually explain what the other repo looks like.
A few specific areas where this matters:
Type and contract coherence. In a monorepo with shared types (a /packages/shared folder, for example), the agent can see that changing an API response shape requires updating the frontend consumer. Across repos, that connection is invisible unless you explicitly describe it.
Refactoring scope. Renaming a field, deprecating an endpoint, or changing an auth flow are cross-cutting concerns. An agent in a monorepo can search, understand, and modify everything atomically. Across repos it becomes two separate sessions with you acting as the bridge.
Testing context. Integration tests that verify frontend-backend interaction live naturally in a monorepo. The agent can run them, see what breaks, and fix both sides in one pass.
Monorepos are not free. CI complexity scales with repo size. A change in a shared utility triggers builds and tests across every project in the repo. Google solved this with Bazel and massive infrastructure investment, but most teams are not Google. The tooling tax (Nx, Turborepo, build caching, affected-project detection) is real and adds its own layer of complexity. AI agents do not make your CI pipeline faster.
Context windows are finite too. A massive monorepo with 500k lines is going to hit token limits regardless of how well-structured it is. What matters more than repo structure is organization within the repo: clear module boundaries, good naming, and well-organized directories. A chaotic monorepo can actually be worse for an agent than two clean, well-documented repos with a shared API spec.
Conway's Law has not been repealed. Architecture follows organizational structure, not tooling. If two teams own two services with different deployment lifecycles, forcing them into one repo for AI convenience creates human coordination problems. AI optimizes the coding phase, but software delivery is still a people problem.
Cross-repo tooling is catching up too. MCP servers can index your API schema, your frontend types, and your deployment config across repos and give an agent functionally equivalent context to a monorepo. In some cases the context is arguably better because it is curated rather than "here is everything, figure it out." Think of it like a database index versus a full table scan.
The likely future is that repo structure becomes less important as tooling abstracts it away. The agent of 2028 probably will not care whether your code lives in one repo or five. It will have indexed access to all of it, understand the dependency graph, and operate across boundaries seamlessly. The monorepo advantage we feel today is real, but it might be a symptom of tooling immaturity rather than a fundamental architectural truth.
There is another monorepo win that gets less attention: the agent's own configuration lives alongside the code it operates on.
In an AI-first workflow, your project carries more than just source code. It has agent rules (CLAUDE.md, .cursorrules, AGENTS.md) that define project conventions and constraints. It has skills that encode task-specific playbooks, like how to build a chart component or how to write a migration in your project. It has architecture decision records that capture why the project uses certain libraries or patterns. And it has the codebase itself, which serves as a living reference for how things are actually built.
In a monorepo, all of this is available to the agent in a single context. The agent reads the rules, understands the conventions, looks at existing components for reference patterns, and implements the new feature following the established approach. There is no gap between "what the agent knows about the project" and "what the project actually looks like." The rules file says "use MUI X Charts Pro for all chart components," and three directories over the agent can see exactly how the team has used that library before.
In a multi-repo setup, this knowledge gets fragmented. Each repo might have its own rules file, but the project-wide conventions live... where? A shared wiki? A Confluence page the agent cannot read? The senior developer's head? The monorepo keeps the entire knowledge surface in one place: code, conventions, patterns, and agent configuration. A new agent session (or a new team member) can orient themselves from a single starting point.
This matters more than it sounds. The quality of an agent's output is directly proportional to the quality of the context it has. A well-maintained CLAUDE.md in a monorepo with clear conventions and reference implementations will produce better results than a detailed prompt in a repo where the agent has no project knowledge to draw from.
If you are using spec-driven development, having your specs live in the same repo as the implementation is another natural win. The agent can validate conformance in real time, see drift between the spec and the code, and keep both in sync without you acting as the bridge.
That said, there is a growing conversation about whether the current wave of SDD tooling is worth the overhead it introduces. Tools like Kiro, spec-kit, and OpenSpec all propose structured spec workflows, but some practitioners are finding that the maintenance burden of all those markdown files creates its own problems. I have been exploring this topic and I am not entirely convinced the hype around SDD will age well. It reminds me of the early microservices enthusiasm: a good idea applied universally without enough regard for when it actually helps and when it just adds overhead. I will dig into that in a future post.