Git Good
Git Good
Git Good
The Monorepo Wars: One Repo to Rule Them All
S1 E819m · Apr 14, 2026
Google, Meta, and Microsoft all use monorepos—but the real battle isn't about Git, it's about whether your engineering teams can see each other's code.

The Monorepo Wars: One Repo to Rule Them All

The Meeting That Never Ends

This is episode eight of Git Good, Season Two. And if you have ever worked at a company with more than three teams, you have been in this meeting.

Someone pulls up a whiteboard. Or a shared document. Or a Slack thread that should have been a meeting, which becomes a meeting that should have been a Slack thread. The question on the table sounds simple. Should we put all our code in one repository, or should each team have their own?

Two hours later, nothing is resolved. The backend team wants a monorepo because they are tired of updating the same dependency in fourteen places. The frontend team wants separate repositories because the backend team's test suite takes forty minutes and they do not want to wait for it. The platform team wants whatever Google does, because Google seems to have figured this out. The engineering manager wants whatever ships fastest, and is beginning to suspect the answer is "neither."

This meeting happens every day, in companies around the world. It has been happening for over a decade. It will happen tomorrow. And the reason it never gets resolved is that both sides are right, both sides are wrong, and the real question has nothing to do with Git at all.

The Argument in Two Sentences

Episode five introduced the gap, the space between the twelve-person startup and the companies that built custom infrastructure to make Git work at planetary scale. This episode tells the argument that lives inside the gap. The one about people.

A monorepo says: we are one team. All the code lives together. Any engineer can see any file. When someone changes an interface, they fix every caller in the same commit. The build breaks for everyone or nobody. Coordination happens through the code itself.

A polyrepo says: we are many teams. Each group owns a repository. You publish versioned interfaces and other teams consume them when they are ready. Some upgrade immediately. Some upgrade next quarter. Some never upgrade, and that is their problem now.

The monorepo advocate says this creates atomic changes and shared visibility. The polyrepo advocate says this creates autonomy and independent deployments. The monorepo advocate says polyrepos lead to dependency hell. The polyrepo advocate says monorepos lead to build hell. They are both describing real things that happen to real teams. That is why the argument never ends.

But here is the part that rarely makes it onto the whiteboard. In nineteen sixty-seven, a computer scientist named Melvin Conway submitted a paper to the Harvard Business Review. They rejected it. He sent it to Datamation instead, and they published it in April nineteen sixty-eight. The paper was called "How Do Committees Invent?" and its core observation was brutal in its simplicity.

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.

Fred Brooks picked it up in The Mythical Man-Month and gave it a name. Conway's Law. And Conway's Law is the ghost haunting every monorepo debate, whether anyone invokes it or not. Your repository structure will mirror your organizational structure. If your teams talk to each other constantly, a monorepo will feel natural. If your teams operate as independent units, polyrepos will feel natural. The architecture is not the cause. It is the symptom.

Some organizations have tried to weaponize this. They call it the Inverse Conway Maneuver: deliberately restructuring your teams to produce the architecture you want. If you want microservices, you create small autonomous teams. If you want a unified platform, you create cross-functional teams with shared ownership. The idea is seductive. Instead of letting the org chart accidentally dictate the architecture, you intentionally design the org chart to produce the architecture you need. In practice, it means your monorepo versus polyrepo decision is not just choosing a repository structure. It is choosing a team structure. And convincing a hundred engineers to reorganize how they work is considerably harder than running a migration script.

The Company with Fifty Repositories

Picture a company. Two hundred engineers. Eight teams. They have been around for seven years. They started with one repository, as most companies do, because there was one team and one product. Then they added a second product. Then a mobile app. Then an internal tool. Then a platform layer. Each got its own repository because each had its own team, and Conway's Law did its work silently.

Now they have fifty-three repositories. Nobody planned this. Nobody made a decision. The repositories accumulated the way dishes accumulate in a sink. And now there are problems.

The authentication library exists in four versions across twelve repositories. Nobody is sure which version has the security patch from last October. Three of the versions are forks that diverged so long ago they have different function signatures for the same operations. A junior developer on the billing team found the vulnerability, patched their copy, and opened a Slack thread asking which other teams needed the fix. Nobody answered for two days. When they did, the conversation revealed that two teams did not even know they were using the library.

A change to the payment API requires coordinated releases across five services, each in its own repository, each with its own deployment pipeline, each owned by a team with its own sprint cycle. Scheduling the coordinated release takes longer than writing the code. The calendar invite has fourteen people on it. Eight of them do not know why they are there. The remaining six cannot agree on a date.

The diamond dependency problem, where two libraries need different versions of the same third library, is no longer a textbook example. It is a daily standup topic. Someone proposes a monorepo. Someone else points out that the Java team, the Python team, and the Node team all have different build systems, and merging them into one repository means merging three build pipelines into one monstrous pipeline that nobody understands. The meeting ends without a decision. Again.

This is the middle ground where most companies actually live. Not Google. Not a startup. Just a company that grew organically and now has to decide whether to consolidate or keep splitting. The company does not need custom virtual filesystems. It does not need a tool that handles billions of lines of code. It needs to decide what kind of organization it wants to be. That is the question the monorepo debate is actually asking, and that is why it feels so difficult. Architectural decisions are easy. Organizational identity is hard.

The Toolmakers

If the monorepo debate is an organizational question, the tools that emerged to answer it reveal something about what organizations actually need.

Victor Savkin was on the Angular team at Google. He saw how Google's monorepo worked from the inside, how any engineer could navigate the entire codebase, how changes rippled through dependencies in a single commit. When he left to co-found a company called Nrwl, the tool he built was called Nx, and its purpose was to give regular companies the monorepo experience that Google had built for itself.

Any company with more than one large product would benefit from a monorepo. But it would not benefit a company that wants to keep their teams distinct from one another.

That second sentence is the one people miss. Savkin is not saying monorepos are universally better. He is saying they are better for organizations that want to be integrated. If your teams want autonomy, if they want to pick their own tools and deploy on their own schedule, a monorepo will fight you every step of the way. The tool does not just manage code. It encodes an organizational philosophy.

Nx does something unusual for a build tool. It analyzes the dependency graph of your entire monorepo and figures out which projects are affected by a given change. If you modify a shared library, Nx knows which applications depend on it and runs only those tests. It generates code. It enforces boundaries between projects. It is less a build tool and more an organizational nervous system.

Then there is Jared Palmer. In two thousand twenty-one, Palmer was working alone on a tool called Turborepo. Where Nx was a full platform, Turborepo was lean. A task runner that cached aggressively and ran things in parallel. Palmer was about to raise a seed round when Guillermo Rauch, the CEO of Vercel, called.

What happened next is a story about leverage. Palmer took Vercel's acquisition offer to Netlify, Vercel's biggest competitor, and started a bidding war. He had term sheets from investors, meaning he could walk away from both companies at any time and simply take funding instead. The negotiation ran all summer. Vercel made an offer he could not refuse, and in December two thousand twenty-one, Turborepo was acquired and open-sourced under an MPL license.

We want to make the monorepo experience as fast and simple as possible. No configuration files. No learning curve. Just speed.

Palmer spent about a year building out Turborepo at Vercel, then moved to directing all of Vercel's open source projects, then helped build the Next.js team. Then he pivoted to AI and built v0, Vercel's AI coding tool. And then, in one of those career arcs that makes the tech industry feel very small, he ended up at Microsoft as a senior vice president of GitHub.

The man who built a monorepo tool now oversees the platform where most of the world's repositories live. Conway's Law, working its way through careers as well as codebases.

And underneath both Nx and Turborepo sits Bazel, the tool Google open-sourced from its own internal build system. Bazel handles polyglot codebases, hermetic builds, and massive scale. It is the tool you reach for when you have a thousand engineers and your monorepo contains Go, Python, Java, and C++ all at once. Bazel's promise is that every build is perfectly reproducible. The same inputs always produce the same outputs, no matter which machine runs them. That sounds obvious until you realize how many build systems cheat by relying on the state of the developer's machine.

The cost is complexity. Configuring Bazel requires a specialized skill set that most companies do not have and cannot hire. There are consultancies whose entire business model is setting up Bazel for companies that adopted it because Google uses it and then discovered that using the tool is not the same as having the team that built the tool. Every feature of Bazel makes sense at Google's scale. At a company with eighty engineers, most of those features are overhead that nobody asked for.

Three tools, three philosophies. Nx says the monorepo should be intelligent, aware of its own structure. Turborepo says the monorepo should be fast and invisible. Bazel says the monorepo should be correct and reproducible. Each one reflects a different answer to the question "what kind of organization are we?" and each one has a community that will defend that answer passionately.

Here is the quiet irony. Both Nx and Turborepo, tools built to manage JavaScript monorepos, are rewriting their own cores in Rust. The tools that exist to make JavaScript codebases manageable at scale are fleeing JavaScript for their own internals. Nobody talks about this, but it says something about the limits of the language they serve.

And here is the deeper irony. The existence of these tools proves the monorepo debate is not actually about whether monorepos are good or bad. It is about whether your organization is willing to invest in the tooling that makes a monorepo work. Google built Bazel because it had to. Savkin built Nx because he wanted regular companies to have what Google had. Palmer built Turborepo because he thought the investment should be minimal. The tool you choose is a bet on how much pain you are willing to absorb up front to avoid pain later. That calculation is different for every organization, which is why the debate never ends.

The Ones Who Picked Wrong

DigitalOcean's UI Platform team migrated to a monorepo. They had a plan. They had staging deployments. They had a migration date. What they did not have was a shared understanding of what the migration actually required.

The team had been using Yarn version one. The monorepo required Yarn version four. Nobody communicated that this upgrade was mandatory, not optional. When the monorepo launched, some developers could not get the repository running at all. They spent the first few days not building features, not fixing bugs, but troubleshooting their own development environments. The thing that was supposed to make collaboration easier had made individual work impossible.

Then came Monday morning. Their staging deployments had worked fine during the migration, but their production deployment pipeline was slightly different, in ways nobody had checked. The automated production pipeline broke first thing Monday. They fixed it before lunch, which is both a testament to good engineering and a damning indictment of the planning that got them there.

DigitalOcean published the postmortem, and the lessons sound obvious in hindsight. Communicate breaking changes before you flip the switch. Test production deployments, not just staging. Create a support plan for the migration period. But these lessons keep needing to be learned because the monorepo migration is not a technical problem with a technical solution. It is a coordination problem, and coordination fails in the same ways every time: assumptions go unchecked, edge cases go untested, and the people who know the most about the old system are too busy supporting it to prepare for the new one.

For every team that publishes their monorepo migration story, there are dozens who quietly reverse course. The pain of migrating to a monorepo is directly proportional to the maturity, size, and number of existing repositories. The more established the codebase, the more languages, the more custom build configurations, the harder the migration. And unlike most migrations, there is no bridge tool. There is no monorepo-svn that lets you try it incrementally. You jump or you do not.

The reverse migration exists too. Teams that went monorepo, drowned in build times and merge conflicts, and split back out into multiple repositories. Their git clone takes twenty minutes, their CI pipeline takes an hour, and the build engineer who was supposed to fix it quit in March. Teams that went polyrepo, lost the ability to make atomic changes across services, and consolidated back. Their cross-service feature took three sprints of coordination instead of one sprint of coding. The grass is always greener in the other repository structure, and the migration to get there always costs more than the estimate.

Two Philosophies, One Industry

Google chose the monorepo because Google believes any engineer should be able to see any code. That is not a technical requirement. It is a cultural value. At Google, a new hire on the Maps team can read the source code for Search. A performance engineer can trace a slowdown across service boundaries without asking anyone for access. The monorepo is not just a repository strategy. It is a statement about how the company believes information should flow.

Netflix chose polyrepos because Netflix believes each team should own their own territory. Each microservice lives in its own repository, with its own deployment pipeline, its own technology choices. The recommendation engine team can use Python while the streaming team uses Java. A deployment failure in one service does not block a release in another. The polyrepo is not just a repository strategy. It is a statement about how the company believes autonomy should work.

Both companies stream video to hundreds of millions of people. Both companies ship code multiple times a day. Both companies are wildly successful. And both would struggle to switch to the other model, not because of the technical cost but because their entire organizational culture is built on the assumptions their repository structure encodes.

The DORA State of DevOps research from two thousand twenty-four found that organizations with clear service ownership, the polyrepo pattern, showed two and a half times faster lead times and fifty percent lower failure rates. But the research also showed that organizations with strong internal tooling, the monorepo pattern, had higher developer satisfaction and less duplicated work.

Both datasets are real. Both conclusions are valid. The question is not which is better. The question is which organizational philosophy you believe in. And that is why the meeting never ends, because most organizations have not decided what they believe. They want the atomic changes of a monorepo and the autonomy of polyrepos. They want shared infrastructure and independent deployments. They want the thing that does not exist, which is the repository structure that gives you all of the benefits and none of the costs.

The honest answer, the one that rarely survives contact with the whiteboard, is that the choice is about where you want to pay the complexity tax. Monorepo: you pay it in the codebase. Build times, CI infrastructure, merge conflicts that span teams, the build engineer who becomes the most important and most overworked person in the organization. Polyrepo: you pay it in coordination. Version management, dependency audits, cross-service changes that require synchronized releases, and the slow drift toward six incompatible versions of the same library running in production.

You will pay one of these taxes. You do not get to pay neither.

The Map Is Not the Territory

There is a question forming underneath the tooling and the arguments, and it connects to something larger in this season. If an AI assistant can navigate an entire codebase regardless of how many repositories it spans, does the monorepo debate start to dissolve? An AI with a large enough context window does not care whether the code lives in one repository or fifty. It can read across boundaries that would stop a human developer. The monorepo's strongest selling point, shared visibility, matters less when a machine can synthesize visibility from any source. The polyrepo's strongest selling point, autonomy, matters less when a machine can coordinate changes that humans find exhausting.

That is a maybe, and it is too early to know whether it changes anything fundamental. What is not a maybe is this. The monorepo debate is the clearest example of something that runs through every episode this season. Git does not tell you how to organize your code. It gives you primitives, repositories and branches and commits, and lets humans argue about the rest. It was built by a person who managed the largest monorepo in open source, the Linux kernel, using nothing but email and judgment. Git does not have an opinion about monorepos. Git does not have an opinion about anything. It stores content and tracks history and gets out of the way.

The arguments in the architecture meeting are not about Git. They are about trust, autonomy, coordination, and identity. They are about what kind of team you want to be. Conway told us in nineteen sixty-eight that the system would mirror the organization. The monorepo debate is just the latest proof that he was right.

And most teams would rather argue about build tools than answer that question honestly.

That was episode eight of Git Good, Season Two.

Git sparse checkout lets you work in a monorepo without cloning the whole thing. Run git sparse-checkout init, then git sparse-checkout set with the directories you need, and Git will only populate your working tree with those paths. Everything else exists in the repository but stays hidden. It is the compromise position in the monorepo wars: you get the atomic changes and shared history of a single repository, but each developer's machine only contains the code they actually touch. The trade-off is that you need to know which directories matter to you, and Git needs to be told explicitly. It will not guess. It never does.