Free — no signup required

Monorepo Tooling: The Dependency Graph

2 min read

The Problem with "Build All"

In a massive monorepo, you cannot rebuild the entire codebase every time someone changes a single line of code. If the full build takes 4 hours and you have 500 engineers committing 50 times a day, you need a smarter approach. You need to know, precisely, what changed and what that change affects.

Explicit Dependencies via BUILD Files

Tools like Bazel require you to create a BUILD (or BUILD.bazel) file in every directory that contains buildable code. In this file, you explicitly declare:

  1. What targets exist in this package — for example, a cc_binary (C++ executable), a java_library, or a py_test.
  2. Which source files belong to each target.
  3. Which other targets this target depends on, by their fully-qualified label (e.g., //payments/lib:stripe_client).

A minimal Bazel BUILD file for a Go service would define a go_library target naming its source files, its Go import path, and its dependencies — a mix of internal targets (like an auth library or database client, referenced by their fully-qualified label) and external ones (like a third-party HTTP framework) — plus a go_binary target that embeds that library to produce the final executable.

By reading all BUILD files across the entire monorepo, the build tool constructs a massive, fine-grained Directed Acyclic Graph (DAG) — a dependency graph where each node is a build target and each edge represents a dependency relationship.

Selective Building and Testing (Affected Target Analysis)

When you change a file, the build tool:

  1. Identifies which target owns that file (e.g., //lib/auth:auth_lib).
  2. Walks up the dependency graph to find every target that directly or transitively depends on it.
  3. Rebuilds and re-runs tests only for that affected subset.

A change to lib/auth would trigger rebuilds of services/user-api, web/frontend, and mobile/ios-app — but not services/payment-api, which does not depend on lib/auth. A change to a frontend CSS file would not trigger a rebuild of any backend service. This selective execution is the key to keeping CI fast in a monorepo.

Interview Tip

A common interview question is: "How do you avoid running all tests on every commit in a monorepo?" The answer is affected target analysis via the dependency graph. The follow-up is often: "What are the risks?" — the honest answer is that if your dependency declarations are incomplete or incorrect, you can miss rebuilding something that should have been rebuilt, leading to silent breakage. Hermetic build systems catch this at declaration time (the build fails if you use an undeclared dependency), which is why hermeticity and the dependency graph are inseparable concepts.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free