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-ato call a helper function inshared-lib? You couldn't just type a relative path. I had to go into theBUILD.bazelfile ofservice-aand 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 withservice-backend-borservice-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
Software EngineeringBreaking the Rules Safely: When a Tech Lead Purposefully Violates the Liskov Substitution Principle (LSP)
SOLID is not a religion, and design principles are not immutable commandments. From the perspective of a battle-tested Tech Lead, sometimes deciding to bend the Liskov Substitution Principle (LSP) is a mature choice to keep the system alive. Let’s analyze 4 classic trade-off scenarios and the art of safely isolating the 'toxic code'.
Software EngineeringThe Black Charter of Oil & Gas: When Code Architecture Dictates Survival
"What if a software design flaw didn't just cause a bug, but cost human lives? Step onto a semi-submersible oil rig to discover why the Open/Closed Principle (OCP) and Dagger 2 aren't just textbook theories—they are a survival guide for mission-critical architecture." Length: 254 characters Best for: Medium, Dev.to, or LinkedIn articles where you want to hook the reader immediately with a story.
Software Engineering
Discussion
0 Comments
Be the first to start the discussion.