Every development team eventually faces the question: should we put everything in one giant repository or split into many small ones? The answer is rarely about technical purity—it's about workflow friction. Monorepos promise unified versioning and atomic changes; polyrepos offer team autonomy and focused builds. But the daily reality involves pipeline bottlenecks, broken dependencies, and code review delays that can make either model painful. This guide compares the two approaches through the lens of workflow friction, helping you decide which trade-offs your team can live with.
Why This Decision Matters Now
The repository structure you choose ripples through every part of your development lifecycle. It affects how long developers wait for builds, how often integrations break, and how much context they need to keep in their heads. As teams grow from a handful of engineers to dozens or hundreds, the friction from a misaligned repo strategy can become the primary drag on velocity.
Many teams inherit their repository model from an early-stage decision made when the codebase was small. A monorepo that worked well for three developers can become a nightmare of slow CI pipelines and merge conflicts for thirty. Conversely, a polyrepo setup that gave each team freedom can lead to integration hell when services need to change together. The cost of switching later is high—not just in tooling migration but in retraining habits and rethinking branch strategies.
We've seen teams spend months debating this choice while their productivity stagnates. The key is to focus not on abstract principles but on concrete workflow friction points: build times, test reliability, code review complexity, and deployment coordination. Each of these is affected differently by the repo model, and understanding those effects is the first step toward a decision you won't regret.
What's at Stake
At its core, the monorepo vs. polyrepo decision determines how your team experiences change. In a monorepo, a single commit can update a shared library and all its consumers in one atomic operation. In a polyrepo, cross-repo changes require coordinated pull requests, version bumps, and careful release sequencing. The friction shows up in daily standups: “I'm waiting for the shared-lib PR to merge before I can test my service.” Or “The CI pipeline took 45 minutes because it rebuilt everything.”
The right choice depends on your team's size, the coupling between your projects, and your tolerance for coordination overhead. Let's break down the core mechanisms before diving into specific scenarios.
Core Idea: Two Models, One Trade-off
A monorepo places all code—frontend, backend, libraries, configuration—into a single version-controlled repository. A polyrepo splits code into many repositories, typically one per service or component. The trade-off is between coordination cost and isolation benefit.
In a monorepo, coordination is cheap: you can change an API and its consumers in one commit, and the CI pipeline can catch breakages across the entire codebase. But isolation is expensive: a bad commit can break every project, and build times can balloon as the repo grows. In a polyrepo, isolation is cheap: each team owns its repo, builds only what they need, and merges without affecting others. But coordination is expensive: cross-repo changes require versioning, release coordination, and often a painful dance of updating dependencies.
The friction points are not symmetric. Monorepo friction grows with repository size and team count. Polyrepo friction grows with the number of interdependencies between repositories. Most teams underestimate how quickly these frictions compound.
How Friction Manifests
Consider a typical scenario: a shared authentication library used by three services. In a monorepo, a developer updates the library and all three services in one pull request. The CI pipeline runs tests for everything, and if something breaks, the developer fixes it before merging. The friction is the long CI cycle and the risk of breaking unrelated projects. In a polyrepo, the developer updates the library repo, cuts a new version, then updates each service repo to use the new version. The friction is the sequence of pull requests, the version bump process, and the risk that one service lags behind.
Which friction is worse depends on your team's workflow. If you have a fast CI pipeline and good test coverage, monorepo coordination may be smoother. If you have many independent teams with different release cadences, polyrepo isolation may be worth the coordination tax.
How It Works Under the Hood
Understanding the technical underpinnings helps explain why friction appears where it does. Let's look at three key areas: build systems, dependency management, and CI/CD pipelines.
Build Systems
Monorepos require build systems that can handle incremental builds and dependency graphs. Tools like Bazel, Nx, or Gradle can analyze which files changed and build only what's affected. Without such tooling, a monorepo quickly becomes unusable as every commit triggers a full rebuild. Polyrepos naturally limit build scope to the repository, but they require each repo to have its own build configuration, which can drift over time.
The friction point: in a monorepo, you invest upfront in a sophisticated build system; in a polyrepo, you pay the cost of maintaining multiple build configurations and ensuring they stay consistent.
Dependency Management
In a monorepo, dependencies are typically resolved at the file system level—one version of each library, shared across all projects. This eliminates the “dependency hell” of conflicting versions but creates tight coupling: upgrading a library affects all consumers immediately. In a polyrepo, each repo manages its own dependencies via a package manager (npm, pip, Maven). This allows different teams to use different versions but introduces the overhead of publishing, versioning, and updating packages.
The friction point: monorepo coupling can slow down library upgrades because of the blast radius; polyrepo decoupling can lead to version drift and integration surprises.
CI/CD Pipelines
Monorepo CI pipelines must handle the entire codebase, which can lead to long build times. Smart caching and selective testing can mitigate this, but they add complexity. Polyrepo CI pipelines are simpler per repo but require orchestration for cross-repo changes—for example, a pipeline that triggers downstream repos when a shared library is updated.
The friction point: monorepo CI is hard to scale efficiently; polyrepo CI is hard to coordinate across repos.
Worked Example: A Team of 25 Engineers
Let's ground this in a composite scenario. Imagine a team of 25 engineers building a SaaS platform with a web frontend, a mobile app, a backend API, and three microservices. They currently use a monorepo and are considering splitting into polyrepos because of growing build times.
In their monorepo, the CI pipeline takes 30 minutes on average. A developer working on the mobile app must wait for the entire pipeline to run, including tests for the backend and web frontend. They use a build system that can skip unaffected projects, but the dependency graph is complex—the mobile app depends on a shared library that is used by the backend, so changes to that library trigger builds for both. The team spends about 15% of their time waiting for CI.
If they switch to polyrepos, each service gets its own repo and CI pipeline. The mobile app's pipeline runs in 5 minutes. But now, when the shared library changes, the developer must update the library repo, publish a new version, then update the mobile app and backend repos. This involves three pull requests, two version bumps, and coordination with the backend team. The total time for a cross-repo change increases from 30 minutes (monorepo CI wait) to potentially several hours of coordination and review.
The team measures the friction and finds that cross-repo changes happen about twice a week. The monorepo CI wait costs 30 minutes per developer per day, totaling 12.5 hours daily across the team. The polyrepo coordination cost for each cross-repo change is about 4 hours of overhead (meetings, PR management, versioning). With two such changes per week, that's 8 hours of overhead weekly. The monorepo CI wait costs 62.5 hours weekly. By this rough calculation, polyrepos would save 54.5 hours weekly—but only if the team can reduce the frequency of cross-repo changes by better API design or shared ownership.
The scenario highlights that the decision isn't just about raw time but about the type of friction. Monorepo friction is predictable and distributed across all developers; polyrepo friction is sporadic and concentrated on integration points.
Edge Cases and Exceptions
Not every team fits the typical pattern. Here are some edge cases where the conventional wisdom flips.
Open Source Projects
Open source projects often benefit from polyrepos because contributors work independently on different components. A monorepo would raise the barrier to contribution by requiring knowledge of the entire codebase. However, some large open source projects (like Kubernetes or React) use monorepos to manage coordinated releases. The key is contributor workflow: if contributors typically work on one component at a time, polyrepo is friendlier.
Another edge case is when a team has a very fast CI pipeline (under 5 minutes for the entire monorepo). In that case, the coordination benefits of a monorepo often outweigh the isolation benefits of a polyrepo. Fast CI reduces the main friction point of monorepos significantly.
Organizations with Strict Compliance Requirements
Some industries require audit trails for changes to specific systems. Polyrepos can make it easier to isolate changes to a regulated component, as each repo has its own history and access controls. Monorepos can achieve similar isolation with directory-level permissions and CODEOWNERS files, but the setup is more complex.
We've also seen teams that start with a monorepo and later split into polyrepos as they grow. The transition is painful but manageable if they invest in good API contracts and automated cross-repo testing. The reverse switch—from polyrepo to monorepo—is rarer but can happen when teams realize they are spending too much time on version coordination.
Mixed Models
Some teams adopt a hybrid approach: a monorepo for closely related services and separate repos for independent tools or legacy systems. This can be a pragmatic middle ground, but it introduces the complexity of maintaining two workflows. The friction from the hybrid model can be higher than either pure approach if the boundaries are not well defined.
Limits of the Approach
Both monorepos and polyrepos have inherent limits that no amount of tooling can fully eliminate. Recognize these before committing to a strategy.
Monorepo Scaling Limits
Even with the best build systems, a monorepo eventually hits scaling walls. Git operations slow down as the repository history grows. Clone times become impractical for new developers. CI pipelines, even with selective testing, require maintaining a dependency graph that becomes a maintenance burden itself. Some large monorepos (like Google's) rely on custom version control systems and massive infrastructure that most teams cannot replicate.
The practical limit for most teams is around 100 developers or 1 million lines of code, beyond which the friction of the monorepo model becomes significant without dedicated tooling investment. Plan for this ceiling and consider whether you will outgrow it within a few years.
Polyrepo Coordination Limits
Polyrepos face a different limit: the number of cross-repo dependencies. As the dependency graph becomes denser, the coordination cost grows quadratically. Each team must track the release cycles of every repo they depend on. Integration testing becomes a nightmare of version combinations. The limit is not in the codebase size but in the human capacity to manage inter-team communication.
A polyrepo setup with more than 10 interdependent repos often requires a dedicated release engineering team to manage versioning and integration. Without that investment, teams end up with stale dependencies and broken builds.
When Neither Model Works
Some organizations find that neither pure model works well. For example, a team with multiple product lines that share some infrastructure but have independent release cycles may benefit from a monorepo per product line, with shared libraries published as packages. This is effectively a hybrid, but it requires discipline to avoid creating a giant monorepo by accident.
Another limit is organizational culture. If teams are not used to coordinating closely, a monorepo will force them to do so, which can create tension. If they are already siloed, a polyrepo will reinforce those silos. The repository model can amplify existing team dynamics, for better or worse.
Reader FAQ
Should we start with a monorepo or polyrepo for a new project?
For a new project with fewer than 10 developers and a single product, start with a monorepo. It minimizes coordination overhead and lets you move fast. Once the team grows or the product splits into independently deployable services, consider splitting into polyrepos. Starting with a polyrepo for a small team often leads to unnecessary complexity.
How do we decide when to switch from monorepo to polyrepo?
Monitor two metrics: average CI pipeline time and frequency of cross-team changes. If CI time exceeds 20 minutes and cross-team changes happen more than once a week, it's worth evaluating a split. Also watch for developer complaints about long wait times or merge conflicts. A good rule of thumb is to start planning the switch when the team reaches 25–30 engineers.
Can we use a monorepo with microservices?
Yes, many teams successfully use a monorepo for microservices. The key is to have a build system that can build and test only the affected services. Tools like Nx, Bazel, or Turborepo are designed for this. The benefit is atomic changes across services; the risk is that a bad commit can break multiple services simultaneously. Good test coverage and deployment gates are essential.
What about using submodules or subtrees?
Git submodules and subtrees are sometimes used to create a hybrid model, but they add significant complexity. Submodules make it easy to reference a specific version of another repo, but updating them requires multiple steps and can confuse developers. Subtrees copy code from another repo into your monorepo, but merging changes back is painful. We generally advise against these approaches unless you have a very specific need and are willing to invest in tooling to manage the overhead.
In the end, the best repository strategy is the one your team can execute consistently. Both monorepos and polyrepos have been used successfully at scale. The key is to understand the friction points, measure them, and choose the model that minimizes the friction that hurts your team most. Start with a clear decision framework, involve your team in the choice, and revisit it as your organization evolves.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!