Every engineering org with a monorepo eventually reaches the same inflection point: builds are slow, CI is expensive, and someone on the team reads a blog post about how Google builds everything in seconds with Bazel. The conversation starts. “Should we adopt Bazel?” The promise is genuinely compelling — hermetic builds, massive parallelism, remote caching, and incremental builds that only recompile what actually changed. Who wouldn’t want that?
But here’s what the blog posts don’t tell you: build system migrations are among the most painful infrastructure projects a team can undertake. I’ve led two of them now, and I want to share an honest assessment of the current landscape so others can avoid the mistakes we made.
Our Evaluation
We evaluated Bazel, Buck2, and Pants for our 200K LOC TypeScript/Python monorepo with 15 engineers. Here’s what we found.
Bazel: The Gold Standard (With a Gold-Plated Learning Curve)
Bazel is the tool everyone benchmarks against. Used by Google, Stripe, Uber, and dozens of other companies operating at serious scale. The build model is elegant — everything is a target with declared inputs and outputs, builds are hermetic (no implicit dependencies on system state), and the remote execution API means you can distribute builds across a cluster of workers.
But the learning curve is brutal. BUILD files feel like learning a new language (because you are — Starlark). The mental model shift from “run this script” to “declare this target’s dependencies” is non-trivial. Our engineers, who are productive TypeScript and Python developers, struggled with BUILD file syntax for weeks. The community has grown significantly, but documentation still assumes Google-scale problems. When you’re debugging why ts_project isn’t picking up your path aliases, Stack Overflow has three answers and two of them are outdated.
For our 15-person team, Bazel felt like bringing a tank to a knife fight. The power is undeniable, but the operational overhead was disproportionate to our actual build problems.
Buck2: Fast, Modern, and Risky
Meta’s ground-up rewrite of Buck in Rust is genuinely impressive from an engineering standpoint. It’s faster than Bazel in most benchmarks, offers better developer ergonomics with its Starlark dialect, and introduces real innovation in the build graph model — particularly around dynamic dependencies and incremental computation.
But the ecosystem is young. Community plugins are sparse, Stack Overflow answers are rare, and there’s a legitimate concern: Meta built this for Meta. If Meta deprioritizes Buck2 (and large companies have a track record of abandoning open-source projects when internal priorities shift), you’re on your own with a build system that has a small community. The bus factor for the entire project is essentially one company’s continued investment.
Pants: The Underdog That Delivers
Pants surprised us. It’s Python-first with excellent TypeScript support, and it has the friendliest developer experience of the three tools. Setting up Pants took 2 days versus 2 weeks for a comparable Bazel setup. The documentation is clear, the error messages are helpful (a low bar that Bazel still struggles with), and remote caching just works with their cloud offering — no need to set up and maintain your own remote cache infrastructure.
The trade-off: Pants doesn’t support as many languages as Bazel. If you have a polyglot monorepo with Go, Java, Rust, and C++ alongside your TypeScript and Python, Bazel is still the pragmatic choice. But for our TypeScript/Python stack, Pants covered everything we needed.
The Numbers
Here’s what our benchmarks showed across all three tools:
| Metric | npm/pip (baseline) | Bazel | Buck2 | Pants |
|---|---|---|---|---|
| Clean build | 8 min | 12 min | 9 min | 10 min |
| Incremental build | 8 min | 25 sec | 20 sec | 28 sec |
| CI with remote cache | N/A | -62% | -65% | -60% |
| Setup time | N/A | 2 weeks | 1 week | 2 days |
The clean build numbers are counterintuitive — Bazel is actually slower for a full build because of the overhead of its build graph analysis. But nobody does clean builds regularly. The incremental build is the real win: going from 8 minutes to under 30 seconds fundamentally changes how developers work. You save, you build, you see results immediately. The feedback loop tightens dramatically.
Remote caching reduced CI times by roughly 60% regardless of which tool we used — and that’s the most important takeaway from our entire evaluation.
The Controversial Conclusion
Most monorepos under 500K LOC don’t need Bazel. The complexity overhead — BUILD files, Starlark, remote execution infrastructure, the learning curve — doesn’t pay off until you have 50+ engineers and build times measured in tens of minutes. For teams under 20 engineers, Pants or even Turborepo (for JS/TS-only monorepos) gives you 80% of the benefit at 20% of the complexity.
We chose Pants. Six months in, we haven’t regretted it. Our CI times dropped 60%, incremental builds are near-instant, and the migration was completed without a quarter-long productivity hit.
Question
What build system does your monorepo use, and at what team size or codebase scale did you feel the need for a dedicated build tool? I’m curious whether our 500K LOC threshold resonates with others or if we’re being too conservative.