Tags: web-dev concept

Monorepos

Date: 2026-08-17


One repository holding many packages or applications. It makes cross-cutting changes atomic and refactoring safe; it makes CI, tooling and access control harder — and most of the pain is avoidable with task caching that most teams add too late.


A monorepo holds multiple related projects in a single version-controlled repository, with shared tooling and a single commit history.

It is not a monolith. A monorepo can contain a dozen independently-deployed services; a monolith is one deployable unit. They’re orthogonal.

The shape

repo/
├─ apps/
│   ├─ storefront/
│   ├─ admin/
│   └─ api/
├─ packages/
│   ├─ ui/            ← design system
│   ├─ analytics/
│   └─ config/
├─ package.json       ← workspaces
└─ turbo.json         ← task graph

What it genuinely solves

The atomic cross-cutting change — the strongest argument:

MULTI-REPO
  change the design system
  → publish a version
  → PR to storefront, bump, merge
  → PR to admin, bump, merge
  → three PRs, three reviews, and a
    window where they disagree

MONOREPO
  one PR, one review, everything
  updated together
  → CI verifies all consumers before
    merge

You cannot break a consumer without seeing it fail, which is the real benefit — it converts a class of integration failure into a build failure.

Also:

  • One version of everything. No diamond dependency problem
  • Refactoring across boundaries is a normal operation
  • Shared tooling configured once — Linting, Formatting
  • Discoverability. New developers can read the whole system

What it costs

  • CI runtime, unless you only run what’s affected
  • Tooling complexity. Workspace resolution, task orchestration, versioning
  • Repository size, which eventually affects clone and IDE indexing
  • Access control. Git permissions are per-repo, so everyone can see everything
  • Ownership ambiguity. Without CODEOWNERS, nobody owns anything
  • Coupling by convenience. Importing across boundaries is one line, so architecture erodes unless enforced — Static Analysis

That last one is the subtle one. Multi-repo makes coupling costly and therefore deliberate; a monorepo makes it free, and the boundaries need enforcing by tooling rather than by friction.

Task orchestration is the whole game

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": { "dependsOn": ["build"] }
  }
}

^build means “build my dependencies first”, which lets the tool derive the correct order from the dependency graph rather than from a hand-maintained script.

Then the two things that make it fast:

AFFECTED-ONLY    changed packages, and
                 their dependents. Skip
                 the rest

REMOTE CACHE     a colleague's or CI's
                 build result restored
                 rather than rebuilt
                 — Build Caching

See: Build Caching

Without both, a monorepo’s CI is slow enough to undermine the benefit — a full build of everything on every pull request is the single most common monorepo complaint, and it’s a configuration problem rather than an inherent one.

Versioning and publishing

FIXED / LOCKED     everything shares a
                   version
                   → simple, and forces
                     unnecessary bumps

INDEPENDENT        each package versions
                   separately
                   → accurate, more
                     bookkeeping
                   ← usually right for
                     published packages

NOT PUBLISHED      internal packages,
                   consumed from source
                   ← simplest by far

If nothing is published externally, don’t version internal packages at all. They’re always consumed at the current commit, and versioning them is ceremony — Semantic Versioning.

When to use one

GOOD FIT
  a design system shared by several
  apps — Design Systems
  a storefront + admin + API sharing
  types
  one team, or several with high
  overlap
  frequent cross-cutting changes

POOR FIT
  genuinely unrelated products
  teams with no shared code
  wildly different tech stacks
  strict per-team access requirements

See: Design Systems

For a retail team running a storefront, an admin tool and a shared component library, the case is strong — those three change together constantly, and keeping them in step across three repositories is most of the work.