Monorepo Build Systems

Hermetic builds, dependency graphs, remote caching, incremental rebuilds. How Google, Meta, Microsoft, Vercel keep monorepos fast.

Overview

What a monorepo is

A monorepo is a single repository containing multiple projects: services, libraries, frontends. The pattern is mainstream. Google's monorepo is the canonical extreme (~2 billion lines, multi-thousand engineers; Potvin and Levenberg, "Why Google Stores Billions of Lines of Code in a Single Repository," CACM 2016), and Meta (Mercurial-based), Microsoft (Windows on Git, with VFS for Git) and many product companies use it.

The problem build systems solve

Naive monorepo CI runs every test on every change. With 500 packages, even ten-second suites per package mean 80 minutes per CI run, and local builds re-run everything too, killing iteration speed.

> [!IMPORTANT] A monorepo build system's job is incremental, hermetic, cacheable builds: only build and test what actually changed, and share the work across runs and machines.

Three core capabilities

  • Dependency graph — Parse build files (BUILD, project.json, turbo.json, BUILD.pants) into a DAG of targets and dependencies. A change to package A invalidates A and everything that depends on A, but nothing else
  • Hermetic builds — Every source file, dependency and toolchain version that influences a target's output is declared. Same inputs give byte-identical outputs, every time: that is what makes caching trustworthy
  • Remote caching — Artifacts keyed by a hash of all declared inputs, stored in a shared cache. The first developer builds; everyone after, local or CI, gets a cache hit

The tools

  • Bazel — Google, 2015 open-source release of internal Blaze — Multi-language; strict hermeticity; strong remote execution; steep learning curve. Used by Google, Pinterest, Stripe, Dropbox
  • Pants — Twitter, Foursquare; v2 rewrite ~2020 — Python-and-friends focus, then expanded; Rust engine; easier on-ramp than Bazel for Python-heavy stacks
  • Buck2 — Meta, 2023 open source — Rust rewrite of Meta's Buck, designed for Meta scale
  • Nx — Nrwl, formerly an Angular tooling shop — JS/TS focus with growing multi-language support; project-graph based, less strict than Bazel; hosted Nx Cloud remote cache
  • Turborepo — Vercel, acquired ~2021 — JS/TS only; lighter than Nx, simpler config; hosted Vercel Remote Cache
  • pnpm / Yarn workspaces, Lerna — Package-management tier — Not real build systems; often combined with Turborepo or Nx

Key concepts

Monorepo
Single repository containing multiple projects (services, libraries, frontends). Counter-pattern: polyrepo (one repo per project). Trade-offs: monorepo gives atomic cross-cutting changes and shared tooling at the cost of build-system investment; polyrepo is simpler to start but fragments tooling.
Hermetic build
Build whose inputs are fully declared. Same inputs produce byte-identical outputs across machines and time. Foundation for trustworthy caching. Bazel enforces; Nx and Turborepo trust the developer to declare correctly.
Build graph / target graph
DAG of build targets and their dependencies. Tools traverse the graph to compute the minimum work for a given change. The graph is what enables "affected projects" — only build/test what actually changed.
Remote cache
Shared content-addressed store of built artifacts keyed by input hashes. First builder pays; everyone else gets cache hits. With strong hermeticity, cache hits compose: if A is cached and B depends only on A and unchanged sources, B is cached too.
Remote execution
Beyond caching: dispatching build/test actions to a remote compute pool. Bazel's most powerful feature for Google-scale repos. Buildbarn, BuildBuddy, EngFlow are the prominent backends. Overkill below several hundred packages.
Affected projects
In looser tools (Nx, Turborepo): the subset of the monorepo whose tests should run for a given change set. Computed by walking the dependency graph from changed files. The basis for efficient CI in monorepos.

When to use it

  • Designing the build/test strategy for a monorepo with >20 packages and >5 contributors
  • Diagnosing slow CI in a monorepo where every change rebuilds everything
  • Choosing between Turborepo, Nx, and Bazel for a new monorepo
  • Justifying the migration cost from polyglot polyrepo to monorepo with a build system

Interview questions

  • What problem does a monorepo build system solve that pnpm workspaces does not?
  • How does remote caching work, and what does hermeticity have to do with it?
  • When should you choose Bazel over Nx or Turborepo?

Sign up free to read the full topic

More DevOps topics

Start free on Cariara · Coding problems · System design studio