Codebase organisation comparison

Monorepo vs polyrepo

One repository for everything, or one repository per project? The answer drives how teams coordinate, how CI scales, and how easy cross-project changes feel.

TL;DR

  • Monorepo — one Git repository contains many projects. Atomic cross-project commits, shared tooling, single version of truth — at the cost of CI infrastructure investment.
  • Polyrepo — each project owns its repo. Smaller, focused, simpler — at the cost of dependency drift and harder cross-cutting changes.
  • The right choice tracks team coupling. Tightly-coupled teams → monorepo. Loosely-coupled, independent teams → polyrepo.

Side-by-side comparison

AspectMonorepoPolyrepo
RepositoriesOneMany
Cross-project changeOne PR atomic across servicesMultiple PRs coordinated; release ordering matters
Dependency versioningOne version of everythingEach repo pins its own versions — drift inevitable
Code sharingTrivial — import directlyVia published packages with semver
CI scopeMust compute affected projects to stay fastNaturally scoped per repo
ToolingNx, Turborepo, Bazel, Pants required at scaleStandard Git + per-repo CI is enough
DiscoveryOne search across everythingPer-repo search; cross-repo discovery is hard
Access controlPath-based or trust-basedPer-repo, GitHub/GitLab native
CloningSlow as repo grows (shallow / sparse helps)Fast — only what you need
Used byGoogle, Meta, Microsoft, Uber, XMost open-source, most startups

Layout side-by-side

Monorepo

acme/                  ← single repo
  apps/
    web/
    mobile/
    admin/
  services/
    auth/
    billing/
    orders/
  packages/
    ui/                ← shared UI lib
    config/
    types/
  package.json         ← root workspace
  turbo.json           ← build orchestration
  .github/workflows/

Polyrepo

acme/web                ← separate repo
acme/mobile             ← separate repo
acme/admin              ← separate repo
acme/auth-service       ← separate repo
acme/billing-service    ← separate repo
acme/orders-service     ← separate repo
acme/ui-library         ← published as @acme/ui
acme/types              ← published as @acme/types

# Each repo:
#   package.json with deps on @acme/ui@^1.2
#   its own CI, releases, README

When to choose a monorepo

  • Shared design system / types. Frontend, mobile-web, and admin tools sharing a UI library — atomic upgrades are huge.
  • Tightly coupled services. Updating an API contract and all its consumers should be one reviewable change.
  • Standardised tooling. One linter config, one CI template, one dependency upgrade strategy across many projects.
  • Single-org refactoring. "Rename this function everywhere" should be one PR, not 23.
  • You have engineers to invest in CI tooling. Nx/Turborepo/Bazel are not free to set up and maintain.

When to choose polyrepos

  • Independent teams with independent products. No reason to couple their release cycles.
  • Open-source projects. External contributors expect focused, well-scoped repos.
  • Strong service boundaries already. No frequent cross-service changes — coordination overhead is rare.
  • Limited platform team. No one to own monorepo tooling; standard GitHub workflow is fine.
  • Compliance separation. Some code must be visible only to specific teams; per-repo ACLs are simpler than path-based.

English phrases engineers use

Monorepo conversations

  • "This PR updates the shared types and all consumers in one change."
  • "CI is rebuilding everything — we need affected-project detection."
  • "Codeowners for the auth package — review required from the auth team."
  • "Use workspaces for the package linking, not symlinks."
  • "Sparse checkout — junior devs don't need the entire codebase."

Polyrepo conversations

  • "We need to release the library first, then bump it in the consumer."
  • "This is dependency drift — three services on three different SDK versions."
  • "The change spans four PRs across four repos — let's coordinate the merge order."
  • "Renovate bot is keeping all repos on the latest minor."
  • "Open a cross-repo issue — link them so we don't lose track."

Quick decision tree

  • Frontend + design system shared across products → Monorepo
  • Microservices with frequent cross-service API changes → Monorepo (with tooling)
  • Open-source library → Polyrepo
  • Small team, single product, < 10 engineers → Either works; default monorepo for simplicity
  • Independent product teams, weekly cross-team contact → Polyrepo
  • Compliance-isolated codebase (PCI, classified) → Polyrepo
  • No platform team to maintain tooling → Polyrepo
  • You said "monorepo" and your team groaned → Polyrepo — culture matters

Common Mistakes and Trade-offs

A surprisingly common mistake with monorepos is treating them as simply 'bigger' polyrepos. Teams often assume that adding more projects to a single repository automatically improves collaboration or reduces duplication, but this frequently backfires. The increased size introduces significant tooling complexity – build times become crippling, IDE performance degrades dramatically, and dependency management becomes a nightmare without robust infrastructure. This isn't about the number of projects; it's about the interconnectedness and scale. Teams need to invest heavily in dedicated CI/CD pipelines, sophisticated caching strategies, and potentially even separate build environments tailored for specific project types to avoid a catastrophic slowdown. Ignoring this fundamental shift in operational burden is where many monorepo initiatives fail.

At production scale – say, beyond 50-100 projects – the performance bottleneck of a single repository becomes acutely apparent. While polyrepos allow independent deployments and rollbacks, a monorepo's build system can severely restrict release velocity. The cumulative impact of even minor changes across multiple dependencies creates significant contention for resources. This isn't just about IDE sluggishness; it directly translates into increased deployment times, slower feedback loops, and ultimately, reduced development productivity. Polyrepos, despite their initial simplicity, often provide a more predictable and manageable production environment as the codebase grows, allowing for granular control over deployments that are simply impossible with a single, massive repository.

There's a persistent misconception that monorepos always lead to better code sharing and reduced duplication. This assumes a proactive culture of shared components and disciplined reuse—which is fantastic if it exists, but rarely the default. In reality, a monorepo can easily become a dumping ground for orphaned projects, leading to increased complexity and difficulty in understanding dependencies. Teams often end up duplicating logic simply because they don't have a clear, enforced process for sharing code or because changes across different parts of the repository are too risky to integrate directly. Polyrepos force you to explicitly define interfaces and APIs, encouraging genuine reuse rather than implicit dependency on shared code.

Migration between monorepos and polyrepos isn't a straightforward copy-paste operation; it's fundamentally a reorganization of workflows and tooling. Attempting to simply split a large monorepo into smaller repositories without addressing the underlying architectural issues – like inconsistent build processes or lack of dependency management – will just create a collection of smaller, equally problematic polyrepos. A more effective strategy often involves initially adopting a monorepo with carefully designed boundaries and then strategically introducing polyrepos around specific, tightly coupled domains as complexity grows. Furthermore, hybrid approaches—where some core libraries are shared within a monorepo while others reside in separate repositories—can offer a pragmatic balance, but require meticulous governance to avoid creating a tangled web of dependencies.

Frequently asked questions

What is a monorepo?

A monorepo is a single version-control repository containing the code for many projects, services, or libraries — owned by the same organisation. Google, Meta, and Microsoft famously run multi-billion-line monorepos; smaller teams use them for related microservices, design systems, or shared tooling.

What is a polyrepo?

A polyrepo (or "multi-repo") setup gives each project its own version-control repository. This is the default model on GitHub and the historical norm — each service, library, or product lives in a separate repo with its own issues, releases, and access control.

Are monorepos faster to work in?

For atomic cross-project changes, yes — you can update an API and all its consumers in one PR. For everyday work in a single project, polyrepos are usually faster (smaller repo to clone, faster CI, less context to learn).