System designJune 1, 20264 min read

5 Years Ago: A Mid-Level Engineer’s Shock Upon Inheriting a Monorepo "Anchor"... Powered by Bazel

5 Years Ago: A Mid-Level Engineer’s Shock Upon Inheriting a Monorepo "Anchor"... Powered by Bazel

Five years ago, when I was still a mid-level engineer used to simple repositories (polyrepos) where running code was as trivial as npm run dev or go run main.go, my team was handed over a massive cluster of projects.

The Tech Lead from the outbound team handed over the repo with a piece of advice whose sheer "heavyweight" nature I didn't fully grasp at the time: "Everything is in a single repo. We use Bazel to build it."

I eagerly ran git clone, excitedly opened up the codebase, and... completely froze. There were no familiar script files. Staring back at me were dozens of files named WORKSPACE and BUILD.bazel scattered across every single directory. That was the beginning of a grueling yet most rewarding chapter in my career.

1. The Culture Shock of "Explicit Dependencies"

To a mid-level engineer back then, my mindset was simple: if I wanted to use a library, I just imported it; if it was missing, I added it to package.json or go.mod. But stepping into the world of Bazel, that rule was completely shattered.

Bazel operates on a strict philosophy: Hermetic Computing. This means it does not trust anything pre-existing on your local machine.

  • Want a file in service-a to call a helper function in shared-lib? You couldn't just type a relative path. I had to go into the BUILD.bazel file of service-a and explicitly declare: "I am going to depend on the target //packages/shared-lib."

  • Forgot to declare it? Bazel would immediately throw an error at build time, even if your IDE recognized the code perfectly fine.

During the first week of the handover, I spent half my time just... learning Starlark (a Python-like language) to write those BUILD files. It was incredibly frustrating, and I kept asking myself, "Why on earth do people make things so hard on themselves?"

2. And Then... The "Magic" Happened as the System Expanded

Once I climbed over the configuration hurdle and got into the groove of fixing bugs and shipping features, I realized Bazel wasn't a tool for self-inflicted torture—it was an engineering masterpiece designed for large-scale monorepos.

The system we inherited had nearly a dozen services of various sizes. In a typical CI/CD pipeline for a monorepo, every push would mean waiting an hour for the system to re-test and re-build everything. With Bazel, it was a completely different story:

Next-Level "Affected Builds" and "Caching"

Bazel maps out the Dependency Graph of the entire repository like the back of its hand.

  • When I modified a single line of code in service-frontend-a, Bazel knew perfectly well that this change had absolutely nothing to do with service-backend-b or service-mobile.

  • Upon running the build command, it only built service-frontend-a.

  • As for the rest of the services? Bazel pulled them from the cache (even a Remote Cache shared between my machine and the CI/CD server) at speeds measured in milliseconds.

Bazel’s tagline rings true: "Fast and Correct. Choose two." With Bazel, you actually get both. A build is reproducible and consistent; the dreaded "It works on my machine but breaks in production" phrase simply vanished.

A First Taste of a Polyglot Monorepo

The project handed over to us wasn't built on a single language stack. It had a TypeScript frontend, a core service in Go, and several automation scripts in Python.

Without Bazel, our team would have had to install multiple runtimes (Node, Go, Python) locally and deal with painful environment management. With Bazel, it automatically fetched the exact versions of Go and Node into isolated hidden directories and ran them. I only needed to execute a single command: bazel test //..., and all test cases across all three languages ran concurrently and flawlessly.

Epilogue

Five years ago, taking over a monorepo managed by Bazel felt like a driver used to a small-displacement manual car suddenly being thrown into the cockpit of a Boeing 747. It was overwhelming—the control panel was packed with buttons, and a single mistake in a config file could ground the entire "airplane."

Yet, that trial by fire with Bazel is exactly what forged an incredibly disciplined mindset in me regarding Dependency Management and Build Systems. It forced me to look under the hood of the architecture: to understand how my code is actually compiled and how CI/CD pipelines truly operate. It became an invaluable stepping stone, ensuring that I would never be intimidated by any enterprise-grade, massive-scale system ever again.

Related reading

Where Does Real Knowledge Come From in the Age of AI?
Artificial intelligence8 min

Where Does Real Knowledge Come From in the Age of AI?

AI answers everything with the same confident tone, whether right or wrong. The only way to catch its errors is to already know the domain. This essay maps six knowledge sources—books, primary documents, vetted updates, courses, people, and practice—and argues that cross-referencing them is the…

Aug 11, 2026Read
Six Stations, Six Ways to Die: A Request's Journey for Survival
System design17 min

Six Stations, Six Ways to Die: A Request's Journey for Survival

Technical notes & reflection — on the road every request must travel, and why it travels that way.

Jun 14, 2026Read
I Built a DNS Server to Understand the Thing I'd Blindly Trusted for Ten Years
System design14 min

I Built a DNS Server to Understand the Thing I'd Blindly Trusted for Ten Years

There are technologies you use every single day without ever looking them in the eye. For me, DNS was one of them. I'd been typing domain names for a decade. Buying domains, pointing records, waiting for "propagation," cursing when it didn't come up, rejoicing when it did — without really understanding why it came up. DNS, to me, was like the light switch on the wall: flip it and the room lights up; if it breaks, call an electrician. Until one deploy night, the site went down. ping to the IP was fine. curl straight to the IP returned the page. Only the domain name sat there in silence. I stared at it and realized something a little humiliating: I didn't know where to even start fixing it, because I had never truly understood the thing that was broken. So I did what probably only an engineer would find reasonable: instead of skimming the docs, I sat down and wrote an entire DNS server in Rust. The project is called mini-dns. This post is what a black box told me once I finally opened it up.

Jun 13, 2026Read