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

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).