Understand monorepo vs polyrepo trade-offs, how Turborepo and Nx solve the scaling problem, what workspace protocols do, and when a monorepo is the right architectural choice — with the depth senior engineers need for system design interviews.
A monorepo is a single Git repository containing multiple related projects — apps, libraries, design systems, and tools — each with its own package.json but all sharing tooling, CI, and version control history. Think of it as a single office building where each team has its own floor but shares the lobby, elevators, and security system. A polyrepo is each team renting their own building — full independence, but crossing the street every time they need to collaborate.
In a polyrepo, each app or library lives in its own repository. Changes to shared code require publishing a new npm package version, updating dependents, and coordinating cross-repo PRs. In a monorepo, all packages live together — atomic cross-package changes, unified CI, and shared tooling.
A naive monorepo with 50 packages and npm run build --workspaces rebuilds everything on every change. With 100 packages this takes 20 minutes. Turborepo and Nx solve this with content-addressed caching and task graph parallelization.
Turborepo (by Vercel) is a high-performance build system that wraps your existing package.json scripts. It adds a task graph layer on top of npm/pnpm/yarn workspaces.
// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"], // build dependencies first
"outputs": ["dist/**"] // cache these outputs
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
}
}
}
Remote caching: turbo run build --remote-cache stores build artifacts in the cloud (Vercel or self-hosted). If the inputs (source files + dependencies) haven't changed, the cache hit restores the output instantly — CI goes from 10 minutes to 30 seconds.
Nx (by Nrwl) is a more opinionated and feature-rich monorepo framework. It provides generators (scaffolding), executors (build/test/lint runners), a visual dependency graph, and deep integration with frameworks like Next.js, Nest.js, and Angular.
// Run only affected packages since main branch
npx nx affected --target=build --base=main
// Visualise the dependency graph
npx nx graph
Nx's affected command is its killer feature — it analyses your import graph and only rebuilds/tests packages whose source or dependencies changed. This is more precise than Turborepo's file-hash-based caching for large repositories.
| Turborepo | Nx |
|---|---|
| Minimal config, wraps existing scripts | Opinionated, replaces scripts with executors |
| Great for JS/TS monorepos already using workspaces | Great for enterprise projects needing generators/scaffolding |
| Vercel remote cache built-in | Nx Cloud or self-hosted cache |
| Lower learning curve | Steeper, but more power |
pnpm and Yarn Berry support workspace:* protocol — packages reference each other directly without publishing to npm. Changes in a shared library are immediately available to all consumers in the repo without a version bump.
// packages/web/package.json
{
"dependencies": {
"@company/ui": "workspace:*", // always the local version
"@company/utils": "workspace:*"
}
}Monorepos mean one deployable app — a monorepo can contain dozens of apps and libraries, each deployed independently. The repo boundary and the deployment boundary are orthogonal concerns.
Turborepo and Nx replace package managers — they sit on top of npm/pnpm/yarn workspaces. You still need a package manager that understands workspaces; Turborepo/Nx add the smart task running layer.
Monorepos are only for big companies — small teams with shared code (e.g., a web app and a React Native app sharing business logic) benefit significantly from a monorepo.
Git becomes slow in a monorepo — with shallow clones, sparse checkout, and partial clones, git performance in large monorepos is manageable. GitHub/GitLab have specific monorepo optimisations.
Google: the world's largest monorepo (billions of lines of code in a single repo). All internal tools, services, and frontends share the same codebase with a custom build system (Blaze/Bazel).
Meta: React, Jest, and dozens of related packages all live in the facebook/react monorepo — contributors can make atomic changes across packages in a single PR
Vercel: the Next.js repo itself is a Turborepo-powered monorepo — the framework, CLI, docs, and playground are all managed together
Design system teams: a component library, icons package, tokens package, and Storybook all in one monorepo — component changes, token updates, and docs are all committed together atomically
What is a monorepo and what are its advantages over a polyrepo setup?
How does Turborepo's caching work and what makes it fast?
How does Nx differ from Turborepo?
What are pnpm workspaces and why are they preferred in monorepos?
What are module boundary rules in Nx and why do they matter?
Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.