DevPlainly
Comparisons

Monorepo vs Polyrepo: Pros, Cons and How to Choose

Monorepos and polyrepos compared: code sharing, atomic changes, CI speed, ownership, tooling and the team sizes where each one works best.

· 6 min read

Contents
  1. Definitions
  2. Side-by-side comparison
  3. Advantages of a monorepo
  4. Atomic changes
  5. Easy code sharing
  6. Consistent tooling
  7. Visibility
  8. Disadvantages of a monorepo
  9. CI can get slow
  10. Coarser permissions
  11. Scale problems
  12. Tight coupling risk
  13. Advantages of a polyrepo
  14. Disadvantages of a polyrepo
  15. How to choose
  16. A simple monorepo layout
  17. CI path filters example (GitHub Actions)
  18. Migrating between the two
  19. FAQ
  20. Do big companies use monorepos?
  21. Is a monorepo slower to clone?
  22. Can different projects in a monorepo use different languages?
  23. Further reading

Should all your code live in one repository, or should every service and library get its own? Big tech companies are famous for giant monorepos, while many other organizations run hundreds of small repositories. Both approaches work — and both can go badly.

This comparison explains the real trade-offs so you can pick the structure that fits your team today.

Definitions

  • Monorepo: one repository containing multiple projects — for example a web app, a mobile app, an API and shared libraries — usually with tooling that understands the boundaries between them.
  • Polyrepo (or multi-repo): each project, service or library lives in its own repository, with its own history, CI and releases.

A monorepo is not the same as a monolith. A monorepo can contain dozens of independently deployed services; a monolith is a single deployable application, which can live in either structure.

Side-by-side comparison

MonorepoPolyrepo
Code sharingImport directly, always the latest versionPublish packages, manage versions
Cross-project changesOne commit / one pull requestCoordinated PRs across repos
Dependency versionsEasy to keep consistentEach repo drifts independently
CINeeds "affected only" builds to stay fastSimple per repo, but duplicated config
Access controlCoarser (path-level rules)Fine-grained per repository
OwnershipVia CODEOWNERS and folder conventionsNatural per repository
Tooling needsHigher (build orchestration, caching)Lower per repo, higher for coordination
DiscoverabilityEverything is searchable in one placeCode scattered across repos
Git performance at scaleCan degrade with huge historiesNot a concern

Advantages of a monorepo

Atomic changes

Change an API and every client of it in a single pull request. Reviewers see the whole change, CI tests it together, and nothing is ever deployed half-updated. In a polyrepo the same change means publishing a new library version and opening follow-up PRs in every consumer.

Easy code sharing

Shared UI components, types, validation rules or utility functions are just folders. No private package registry, no version bumps, no "which version of the shared lib does this service use?"

Consistent tooling

One linter config, one formatter, one set of dependency versions, one CI pipeline definition. Upgrades — a new framework version, a security patch — happen once, everywhere.

Visibility

Anyone can search the whole codebase, see how an internal API is used and make fixes across team boundaries.

Disadvantages of a monorepo

CI can get slow

Running every test on every change does not scale. You need tooling that builds and tests only the projects affected by a change, plus caching. Tools such as Turborepo and Nx (JavaScript/TypeScript), Bazel and Pants (multi-language) exist for exactly this.

Coarser permissions

Most Git hosts grant access per repository. If contractors or partners should see only part of the code, a monorepo makes that harder.

Scale problems

Very large monorepos can strain Git: slow clones, slow status checks. Features such as sparse checkout, partial clone and file-system monitors help, but at extreme sizes companies build custom tooling.

Tight coupling risk

Because it is easy to import anything, projects can become entangled. Clear module boundaries and lint rules that forbid certain imports keep things sane.

Advantages of a polyrepo

  • Clear ownership and autonomy: each team controls its repository, CI, release schedule and tools.
  • Simple, fast CI per repository: the pipeline only ever builds one thing.
  • Fine-grained access control: share exactly the repositories each person needs.
  • Independent versioning: libraries follow semantic versioning and consumers upgrade when ready.
  • Easy to open-source a single component.

Disadvantages of a polyrepo

  • Cross-cutting changes are painful: coordinated PRs, release ordering, temporary compatibility code.
  • Version drift: services end up on different versions of shared libraries and frameworks, and upgrades become large projects.
  • Duplicated configuration: CI pipelines, linters and Dockerfiles copied and slowly diverging.
  • Harder local development when a feature spans several repos that must be cloned, linked and run together.

How to choose

Pick a monorepo when:

  • One team (or a few closely collaborating teams) works across frontend, backend and shared code.
  • Changes often touch several projects at once.
  • You want consistent tooling and dependencies with minimal overhead.
  • You are a startup or small company — this is the common default, because the coordination costs of polyrepos arrive long before the scaling costs of monorepos.

Pick a polyrepo when:

  • Teams are independent, with separate release cycles and little shared code.
  • Strict access control between projects is required.
  • Projects use very different languages and toolchains with nothing in common.
  • Components are open-sourced or consumed by external parties as versioned packages.

Hybrid setups are common: a monorepo per product or domain, with truly independent systems in separate repositories.

A simple monorepo layout

my-product/
├── apps/
│   ├── web/          # Next.js frontend
│   └── api/          # FastAPI backend
├── packages/
│   ├── ui/           # shared React components
│   └── config/       # shared lint/TS config
├── .github/workflows/
├── Makefile          # one command menu for everything
└── README.md

Start without heavy tooling: workspaces in your package manager (npm, pnpm or Yarn workspaces), a Makefile as the shared entry point, and CI path filters so the API pipeline only runs when apps/api/ changes. Add a build orchestrator when CI time actually becomes a problem.

CI path filters example (GitHub Actions)

on:
  pull_request:
    paths:
      - "apps/api/**"
      - "packages/config/**"

Migrating between the two

  • Polyrepo → monorepo: you can preserve each repository's history by importing it into a subfolder (for example with git filter-repo --to-subdirectory-filter followed by a merge with --allow-unrelated-histories). Move one repository at a time and fix CI as you go.
  • Monorepo → polyrepo: extract a folder with its history using git filter-repo --subdirectory-filter, publish shared code as packages, and replace direct imports with versioned dependencies.

Either migration is a project, not an afternoon — which is a good reason to choose deliberately at the start.

FAQ

Do big companies use monorepos?

Several famous ones do, with extensive custom tooling. Many others use polyrepos or hybrids. Their choice is driven by their scale, which is rarely yours.

Is a monorepo slower to clone?

At small and medium sizes, the difference is negligible. Very large monorepos use shallow clones, partial clones and sparse checkouts to stay fast.

Can different projects in a monorepo use different languages?

Yes. A Python API and a TypeScript frontend side by side is common. Multi-language build tools help at scale; simple Makefiles or scripts are enough for small repos.

Further reading

Keep reading