Skip to content
Glossary

What Is a Monorepo?

A monorepo is a single code repository that contains multiple projects — web app, mobile app, shared libraries, backend services — managed together with shared tooling.

A monorepo is a single version-controlled repository that holds multiple projects — a web app, a mobile app, shared libraries, and backend services — managed together with one set of tooling, one dependency tree, and one commit history. The opposite is a polyrepo, where each project lives in its own repository.

How a monorepo differs from a polyrepo

The practical difference shows up the moment you change shared code.

In a polyrepo, updating a shared utility means: edit it in repo A, publish a new package version, then bump that version in repos B and C and merge each separately. A single logical change becomes three or four pull requests across days.

In a monorepo, you change the utility once and every project that imports it gets the update in the same commit. One pull request, one review, one CI run that tests everything the change touched.

MonorepoPolyrepo
Shared code changeOne commit, atomic across appsPublish + version bump per repo
Dependency versionsSingle source of truthCan drift per repo
CI scopeTest only affected packagesEach repo runs independently
Access controlCoarser (whole repo)Fine-grained per repo
Tooling setupOne config, sharedRepeated per repo

What goes inside one

A typical product monorepo contains:

  • Web frontend (e.g. a Next.js app)
  • Mobile app (Flutter or React Native)
  • Shared TypeScript type definitions and utilities
  • An API client library used by both web and mobile
  • Backend services or serverless API routes
  • A design-system component library

Each is a separate package or workspace, but they live side by side and import each other directly via the workspace, not via a published registry version.

How it works under the hood

A monorepo relies on two layers:

  • A workspace manager that links local packages so import { x } from '@org/shared' resolves to the folder next door instead of a downloaded node_modules copy. pnpm, npm, and yarn all support workspaces.
  • A build orchestrator that understands the dependency graph between packages so it only rebuilds and re-tests what a change actually affected, and caches the rest.

Common tooling:

  • Turborepo — task orchestration, content-aware caching, and parallel execution; the lightweight default for JS/TS projects.
  • Nx — more opinionated, with generators and a strong dependency graph; suited to large, multi-team codebases.
  • pnpm workspaces — the package-linking layer many Node.js monorepos build on, often paired with Turborepo.

The caching matters: without an orchestrator, a one-line change forces CI to rebuild every package. With one, only the affected slice runs, which keeps CI fast as the repo grows.

When a monorepo is the right call

  • You have two or more apps sharing real code — business logic, types, or an API client.
  • A web app and a mobile app that must stay in lockstep on the same data contracts.
  • You want one pull request to change a shared model and update every consumer atomically, so nothing ships against a stale version.

A concrete case: a booking product with a Flutter customer app and a separate admin web app share booking types, availability logic, and payment models. In a monorepo, changing the booking schema updates both apps in one commit and CI verifies both before merge — no version-skew window where the two disagree.

When it is overhead

For a solo MVP with one web app and nothing to share, a monorepo adds configuration you do not need yet. A single-package repository is simpler to reason about, faster to clone, and has no workspace wiring to maintain.

The honest rule: start with one plain repository, and migrate to a monorepo when you have actual shared code across two or more apps — not in anticipation of it. Premature monorepo setup is a frequent early-stage time sink.

Common mistakes

  • Confusing monorepo with monolith. A monorepo is about repository layout; a monolith is about runtime architecture. A monorepo can hold many independently deployed services.
  • Skipping the build orchestrator. Without caching and affected-only runs, CI time grows with the whole repo, not with your change.
  • No clear package boundaries. If everything imports everything, you lose the ability to test packages in isolation and the dependency graph becomes meaningless.
  • Adopting it too early. Building a monorepo before there is shared code is overhead with no payoff.

Key takeaways

  • A monorepo is one repository with many projects sharing tooling, dependencies, and history.
  • Its core benefit is atomic, single-commit changes to shared code across multiple apps.
  • Use Turborepo or Nx with workspaces so CI only rebuilds what changed.
  • Adopt it when you genuinely share code across apps — not before.

Need a web + mobile product structured this way, with shared types and one CI pipeline? Contact for a quote.

Continue reading

Want this built?