Bazel Book

Bazelisk & .bazelversion

When you open a Bazel project for the first time, you won't install or manage the Bazel binary yourself. Instead, you'll use Bazelisk — a version-aware wrapper that reads a .bazelversion file, downloads the correct Bazel binary, and runs it1. This mechanism ensures every developer on the team builds with the exact same Bazel version, without manual coordination.

Why Not Install Bazel Directly?

Bazel releases new major versions roughly annually (Bazel 7, 8, 9...), and each project pins to a specific version. If you download a Bazel binary from the GitHub releases page, you might end up with a different version than your team — and version mismatches cause subtle, hard-to-diagnose build failures1. Bazelisk eliminates this problem entirely.

How It Works

Bazelisk is typically installed on your PATH as bazel. When you type bazel, you're actually running Bazelisk, which:

  1. Looks for a .bazelversion file in the current directory or any parent directory.
  2. Downloads the specified Bazel version (if not already cached locally).
  3. Delegates the command to that version.

This is transparent — you use bazel build, bazel test, and other commands as if Bazel were installed directly.

The .bazelversion File

This is one of the first files you'll see at the root of a Bazel project2. It contains a single line: the Bazel version number.

9.0.0

That's it. When Bazelisk reads this file, it knows exactly which binary to fetch. The file is checked into version control, so cloning the repository is enough to guarantee the correct Bazel version.

Installing Bazelisk

On macOS, the most common method is Homebrew1:

brew install bazelisk

On other platforms (Linux, Windows), you can download a binary from the Bazelisk releases page: pick the artifact for your OS and architecture, rename it to bazel, and put it in a directory on your PATH (or symlink it there under that name). Alternatively, install via NPM:

npm install -g @bazel/bazelisk

After installation, the bazel command on your system is Bazelisk. You can verify with bazel version, which shows both the wrapper version and the underlying Bazel version1.

.bazeliskrc

Some teams also use a .bazeliskrc file to configure Bazelisk behavior — for example, pointing it at the Aspect CLI, an extended Bazel wrapper with additional developer tooling (covered in 3.5.4 Aspect CLI Extensibility). Like .bazelversion, this file is checked into the repository, so team-wide configuration is automatic2.

key takeaway

You never install a specific Bazel version manually. You install Bazelisk once, and .bazelversion in each project handles the rest. This version-pinning mechanism is the foundation of reproducible builds — before you even write a BUILD file, the build tool version itself is locked down.

extra

How Bazelisk Resolves the Version

When Bazelisk starts, it walks a priority chain to decide which Bazel version to use3:

  1. The USE_BAZEL_VERSION environment variable — highest priority. Useful for one-off testing (USE_BAZEL_VERSION=8.1.0 bazel build //...) without modifying checked-in files.
  2. A USE_BAZEL_VERSION entry in .bazeliskrc at the workspace root.
  3. A .bazelversion file in the current directory or any parent directory.
  4. The USE_BAZEL_FALLBACK_VERSION environment variable — a safety net with configurable behavior (error:, warn:, or silent: prefix).
  5. If nothing is set, Bazelisk falls back to the latest stable release — but this is essentially random drift and defeats the purpose of version pinning. Always pin explicitly.

Beyond exact version numbers like 9.0.0, Bazelisk understands several other formats3:

  • 8.x — floating version, resolves to the latest release in the 8.x LTS series.
  • 8.1.0rc2 — release candidates for testing upcoming releases.
  • Git commit hashes — for testing specific Bazel commits.
  • last_green / last_rc — latest CI-passing commit or most recent release candidate, used by contributors working on Bazel itself.

For day-to-day work, always use an exact pinned version — the other formats are for debugging and migration scenarios covered later.

Bazelisk also supports tools/bazel wrappers and custom Bazel forks — these are maintainer and infrastructure concerns covered in later levels.

Check your understanding

1.What does Bazelisk do when you run `bazel build`?

2.Why is installing Bazel directly (without Bazelisk) discouraged?

3.Where does .bazelversion typically live in a project?

Answer all questions to check

Footnotes

  1. Bazel Training 101 (Part 5): Installing Bazel — Bazelisk as recommended installation method, .bazelversion behavior, available via Homebrew and NPM 1 2 3 4

  2. Bazel 101 Training (Part 6): Create a repository — .bazelversion and .bazeliskrc as key repository files 1 2

  3. Bazelisk README — version resolution algorithm, version formats, and full configuration reference 1 2