Monorepo vs Polyrepo: Choosing a Repository Strategy for a Small Team

Monorepo vs Polyrepo: Choosing a Repository Strategy for a Small Team DevOps

Three developers, two apps and one shared component library. Someone asks whether the library needs its own repository, and a forty-minute debate about tooling follows. It is worth taking seriously — but it is not a question of taste. It is a question of where you want to spend coordination effort: in build tooling, or in process.

What each model actually means

A monorepo holds several projects in one repository, usually with a workspace tool linking them. A polyrepo gives each deployable unit its own repository, plus a home for shared packages. Everything else is variation.

Neither label guarantees anything by itself. A monorepo without a task graph is a large folder that happens to contain three apps. A polyrepo whose helpers get copy-pasted between repos is a monorepo in disguise, only slower and with more merge conflicts.

Build tooling: what you get and what it costs

Polyrepo build tooling is boring, and boring is underrated. Each repository carries its own scripts, Dockerfile and pipeline, so a new service is running by the end of the afternoon. The cost arrives later: bumping a Node version, a lint rule or a base image means opening the same pull request five times, then chasing the stragglers.

A monorepo moves that work into configuration. You need workspaces (pnpm, npm or Yarn), a task runner such as Turborepo, Nx or Bazel, and a cache — local at first, remote once the team is distributed.

Have these in place before you commit

  • One lockfile, so dependency versions cannot drift between projects.
  • A task graph that knows which package depends on which, so a change to the design system does not retest the marketing site.
  • Shared TypeScript, lint and formatting configs that are extended, not copied.
  • CODEOWNERS per package, so reviews still reach the right people.
  • Two documented commands for newcomers: install, and run everything.

Skip those and the monorepo feels slower than separate repos within a month. Get them right and a refactor across four packages is one pull request.

CI costs and pipeline design

The classic monorepo trap is a pipeline that runs every test on every push. A four-minute build becomes twenty, and people start batching commits to dodge the queue — the opposite of what you wanted.

Filtering by affected projects fixes most of it: run only the tasks whose inputs changed, plus their dependants. Remote caching lets a colleague's machine reuse what CI just built, and the other way round. You are billed for compute minutes and cache storage, so check your provider's plan rather than assuming a monorepo costs more. With good caching, it often does not.

Polyrepo CI multiplies pipelines but keeps each one small. The hidden cost is the gaps between them: integration tests spanning two services need scheduled runs or dispatch triggers, and those are the tests that catch real breakage. Whichever model you choose, the number that matters is not the monthly bill. It is how long a developer waits for a green tick.

Sharing code between projects

This is where the two models differ most in daily life. In a monorepo, an internal package is imported straight from source. Rename a prop, update three call sites, ship one commit that passes or fails as a whole. No version to publish, no upgrade pull request to forget.

In a polyrepo, shared code is a release: bump the version, write a changelog, publish to a private registry, then open upgrade pull requests in each consumer. That ceremony earns its keep when the package has real consumers — other teams, or the public. It is pure overhead when the only consumer sits two desks away.

Git submodules and direct Git dependencies look like a middle ground and usually are not. You trade semver for pinned commit hashes, and drift stays invisible until something breaks.

The practical test: if two projects will change together in the same week more often than not, they belong in the same repository.

Onboarding and everyday work

Monorepo onboarding is one clone, one install, one search box. New starters can read the whole system, which matters on a team of five where everyone touches everything eventually. The costs are size and permissions: clone times grow, search returns packages you will never open, and unless your host supports path-level access, write permission covers the lot.

Polyrepo onboarding is a tour — here are the seven repositories, here is the access form, here is the repository map in the handbook that is six months out of date. Clones are fast and ownership is obvious, but a feature spanning API and front end becomes three pull requests, three reviews and a manual deployment order.

A decision checklist for a small team

  1. How often does shared code change? Weekly changes point to a monorepo; a stable library consumed across teams can stand alone.
  2. Do services deploy independently? If release cadence and on-call are genuinely separate, polyrepo keeps that boundary honest.
  3. Is there an external consumer? Public or cross-organisation packages usually deserve their own repository and a proper release process.
  4. Who maintains the build? A monorepo needs one person willing to own the task graph.
  5. What does access control require? Regulated data or contractor access can force a split regardless of tooling preferences.
  6. How reversible is the choice? Merging repositories with history is fiddly; splitting one is worse, because pull requests and issue links break.

How to decide this week

Pick the two projects you suspect will move together and run a two-week spike: put them in one workspace, wire up affected-only CI, and see whether the pipeline gets faster or slower. Leave the rest where they are. Most small teams end up with a mostly-mon

Photo: jarmoluk / Pixabay