Bazel

Bazel is the open-source version of Google's internal build system, Blaze. It builds and tests software in many languages — C++, Java, Go, Python, TypeScript, Rust, and more — from one dependency graph, with a strong guarantee: given the same inputs, a build step produces the same outputs. Because every action declares its inputs exactly, Bazel can cache results, skip anything unaffected by a change, and distribute work across remote machines. In a large monorepo, that turns hour-long builds into minutes.

That power has a price. Bazel asks you to declare dependencies precisely, adopt its rules for each language, and sometimes fight ecosystems built around their own tools. It pays off most for large, multi-language codebases with many contributors; small single-language projects rarely need it.

TL;DR

Quick Example

Declare dependencies in MODULE.bazel and targets in BUILD.bazel:

visibility makes dependency rules enforceable: only targets under //services may depend on the pricing library.

Core Concepts

Packages, Targets, and Labels

Rules and Starlark

Rules define how to turn inputs into outputs. Language rule sets — rules_cc, rules_java, rules_go, rules_python, rules_js, rules_rust, rules_oci for container images — provide them. Custom rules and macros are written in Starlark, a deterministic, Python-like language. Tools such as Gazelle generate and update BUILD files for Go, Protocol Buffers, and other languages.

Bzlmod

Bzlmod manages external dependencies through MODULE.bazel and the Bazel Central Registry, with version resolution across the dependency graph. It replaces the older WORKSPACE mechanism, which recent Bazel releases disable by default.

Hermeticity and Sandboxing

Each build action — compiling a file, linking, running a test — declares its inputs and outputs. Bazel runs actions in a sandbox that exposes only declared inputs, so undeclared dependencies fail loudly instead of working by accident on one machine. Toolchains (compilers, SDKs, interpreters) are also declared, so builds do not depend on what happens to be installed.

Caching and Remote Execution

Remote caching and execution use the open Remote Execution API, implemented by services such as BuildBuddy, EngFlow, and NativeLink, and by self-hosted options such as Buildbarn.

Bazel in CI

When Bazel Fits

Alternatives: Buck2 (Meta, similar model), Pants (strong Python support), Gradle (JVM), Nx and Turborepo (JavaScript monorepos). See Monorepos and Build Tools.

Best Practices

Keep Targets Small

Fine-grained targets give better caching and parallelism, and make dependency graphs meaningful.

Enforce Visibility

Use visibility to encode architecture rules — which libraries may depend on which — and let the build enforce them.

Invest in Toolchains

Declare compilers and SDKs as toolchains rather than relying on host installations, so builds are reproducible on every machine.

Automate BUILD File Maintenance

Use generators such as Gazelle where available, so developers are not hand-editing dependency lists for every import.

Common Mistakes

Non-Hermetic Actions

Giant Catch-All Targets

Adopting Without Ownership

FAQ

What is Bazel used for?

Building and testing large codebases, especially multi-language monorepos, with reproducible results, caching, remote execution, and precise dependency tracking.

Why are Bazel builds fast?

Because actions are hermetic and content-addressed, Bazel can reuse cached results from any previous build — locally or from a shared remote cache — and run independent actions in parallel, including across remote machines.

What is Bzlmod?

Bazel's module system for external dependencies, defined in MODULE.bazel and resolved from registries such as the Bazel Central Registry. It replaces the older WORKSPACE file.

Is Bazel worth it for a small project?

Usually not. Its benefits grow with codebase size, language diversity, and team count. Small projects are typically better served by their language's standard build tools.

What is remote execution?

Running build and test actions on a cluster of remote workers instead of the local machine, sharing their results through a remote cache. It parallelizes builds far beyond one machine's cores.

Related Topics

References