Skip to main content
Living with a build system in your repository goes through a few distinct phases:
  1. One-time setup — “set and forget”, either by running a wizard/installer command or by an expert who has done it before.
  2. Write code — the day-to-day work.
  3. Add a dependency — there needs to be an easy path to declare this to the tooling, ideally an auto-fix built into the IDE.
  4. Maintenance — roughly yearly, dealing with churn and upgrades.
Typical build systems are set up by an expert, then operated by product engineers. As the DevOps movement brings specialization, these are increasingly different people with different skill sets: Why is operating the build easier in other build systems?
  • More mature tooling for a product engineer adding dependencies.
  • A coarse-grained dependency graph that doesn’t need much editing.

Bazel (by itself) leaves a gap

Out of the box, Bazel pushes the dependency graph onto the people least equipped to maintain it:
  • It forces product engineers to manually express their dependency graph before invoking bazel.
  • BUILD files are written in Starlark. Engineers don’t want to learn a new language just to interact with the build tool — even though it’s a Python dialect.
  • Unlike alternatives such as Buck2, Bazel doesn’t allow a dynamic dependency graph based on file contents. So BUILD generation is needed as a workaround: read the file content before Bazel runs and declare the correct graph.
The rest of this course is about closing that gap with Gazelle, so product engineers can keep writing code and let tooling maintain the BUILD files.