Turborepo, Nx, and Bazel: Build Systems for Monorepos
How Turborepo builds a dependency graph from your package.json files — and where Nx and Bazel fit when you need more.
Workspaces give you the package resolution. What they don't give you is the intelligence about what to build, in what order, with what cached from last time. That's what build orchestration tools handle.
What Turborepo Actually Does
Turborepo reads your package.json files, looks at the dependencies and devDependencies declared in each, and builds a directed acyclic graph (DAG) of the relationships between packages.
If dashboard depends on ui and shared, and analytics depends only on shared, Turborepo knows:
- Build
sharedfirst (nothing depends on it) - Then build
uiandanalyticsin parallel (they only depend onshared) - Then build
dashboard(depends on bothuiandshared)
This ordering happens automatically. You don't write it — it's derived from the dependency declarations you already have. Turborepo also detects circular dependencies (which, as someone who accidentally created one, I can confirm are an afternoon of debugging that nobody wants).
Beyond ordering, Turborepo tracks what's changed since the last build. It hashes the contents of each package's output directory. If the hash hasn't changed, it's a cache hit — no rebuild needed.
The Three Tools and When They Apply
Turborepo — low opinions, just runs your npm scripts in the right order with caching. Works with whatever build tool you're already using. Ideal starting point for most teams.
Nx — more opinionated, from the Angular ecosystem. Has opinions about project structure, generates code, manages linting configuration across the monorepo. More powerful, but you're signing up for its conventions. Worth it if you're in the Angular ecosystem or if you want the full structure it provides.
Bazel — Google's build system. Supports multiple languages, designed for truly massive codebases. If you don't know whether you need it, you don't. If you've outgrown Turborepo and Nx and you're managing frontend at Google-scale, this is what exists for that.
My recommendation: start with Turborepo. It's the lowest friction entry point, and the concepts transfer if you ever need to move to Nx or Bazel later.
The turbo.json
The entire Turborepo configuration lives in one file. Here's the shape of what it looks like:
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"type-check": {
"dependsOn": ["^build"]
},
"lint": {},
"test": {
"dependsOn": ["build"]
},
"dev": {
"persistent": true,
"cache": false
}
}
}"dependsOn": ["^build"] means: before running build for this package, run build for all its dependencies first. The ^ means "from dependencies." Without the ^, it means "run this task first in the same package."
"outputs": ["dist/**"] tells Turborepo what to hash for cache invalidation. If the files in dist/ haven't changed, it's a cache hit.
"persistent": true on dev tells Turborepo not to wait for it to finish — it runs indefinitely and shouldn't block other tasks.
The $schema line is optional but valuable: it gives you IntelliSense and type checking on the config file in VSCode. A small thing that saves time debugging misconfigured JSON.
Why This Matters for Design System Teams
Here's the scenario I've seen play out: a design system team wants to update a component's props. In a polyrepo setup, they publish a new version, hope all consuming teams upgrade, and often discover breakage in production weeks later when a team finally does the upgrade.
In a monorepo with Turborepo, they make the change. TypeScript immediately flags every consumer that's broken. CI runs — and because the design system is at the bottom of the dependency graph, Turborepo correctly runs tests for all packages that depend on it. The breakage is caught before any PR merges.
That's the structural guarantee monorepos give you. Turborepo makes that guarantee fast enough to be practical.
Keep reading
Enjoyed this? Get more like it.
Deep dives on system design, React, web development, and personal finance — straight to your inbox. Free, always.