Monorepo
A single version-controlled repository holding many projects/services together, versus polyrepo (one repo per project). A structural decision in the version-control + build corner of developer-tooling — it changes how dependencies are shared, how builds scope, and what the VCS must handle.
What it solves: dependency drift
The case for a monorepo is coordination. In polyrepo, shared libraries are published as independently-versioned artifacts, so services drift onto different versions — “diamond dependency” runtime surprises, duplicated upgrades, and multi-repo coordinated deploys. A monorepo resolves shared dependencies from source at a single revision and lets a change span many projects in one atomic commit. Block consolidated ~450 JVM repos for exactly this reason.
What it costs: builds, VCS, and a platform team
The case against is that scale moves the cost elsewhere:
- Build/CI scaling — you can’t rebuild everything on every commit, so you need dependency-graph analysis + selective/incremental builds and merge queues (Block ran 8,800 builds/week at p90 CI ~10 min via exactly these).
- VCS performance — a giant repo strains Git, pushing teams toward sparse checkouts and, at the extreme, purpose-built VCS for huge trees (lore‘s content-addressed/on-demand-hydration design is the engine-side answer to the same scaling pressure).
- A funded platform team — the load-bearing caveat from block-monorepo-migration: “if you can’t commit to properly funding a platform team… you’ll probably do better with a polyrepo.” Monorepo trades per-team coordination overhead for centralized platform investment.
Build-tool options
Build systems built for monorepos (Bazel, Buck, Pants, Nx, Turborepo) provide the selective-build graph; notably Block built custom Gradle/IntelliJ tooling instead of adopting Bazel, a reminder that the concept is separable from any one tool.
Related
block-monorepo-migration · lore · developer-tooling · synthesis