Bazelisk: a version-aware launcher that replaces the bazel binary
A user-friendly launcher for Bazel.
At a glance
- What is it?
- Bazelisk is a Go wrapper that resolves which Bazel version a workspace needs, downloads it, and forwards your arguments to the real binary. It is useful when several repositories pin different Bazel releases, and unnecessary when you only ever build one project with one version.
- Who is it for?
- Adopt Bazelisk if your repositories pin different Bazel versions in .bazelversion, or if you want a checked-in launcher that lets a newcomer build without installing Bazel first. Skip it if you build one project against one Bazel release and manage that binary with your own tooling, since the wrapper adds a download step and a resolution order you have to understand.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The version mismatch Bazelisk exists to remove
Bazel is pinned per repository. A project that builds with one release can fail on another, and the README names incompatible Bazel versions as "often a cause for frustration and failing builds". Bazelisk targets that gap. It is for repository owners who want to commit a version file, and for developers who work across several Bazel projects at once and do not want to keep swapping binaries in PATH. It is also for the case the README describes directly: checking the launcher into a repository and telling people to run ./bazelisk build //my:software, so that someone who has never installed Bazel can still build the software. The wrapper is not a build system and does not change Bazel's behaviour; it only decides which Bazel binary runs.
How Bazelisk resolves a version, in priority order
The resolution algorithm is a fixed sequence, and each step wins over everything below it. First, a nonempty USE_BAZEL_VERSION environment variable. Second, a USE_BAZEL_VERSION entry in a .bazeliskrc file at the workspace root. Third, a .bazelversion file in the current directory or any parent directory, searched recursively. Fourth, USE_BAZEL_FALLBACK_VERSION, whose prefix decides the behaviour: error: aborts version detection, warn: prints a warning and uses the version after the prefix, silent: uses it without a warning. If none of those apply, Bazelisk uses the official latest Bazel release. That ordering matters in practice: a developer with USE_BAZEL_VERSION exported in a shell profile overrides the version the repository pins, and the build silently runs on something the project never tested. Version labels are not limited to plain numbers. latest means the latest stable release, latest-1 and latest-2 step back through previous releases, 4.x returns the latest release from the LTS series started by Bazel 4.0.0, and 4.* returns the latest release or candidate from that series. A fork can be selected with <FORK>/<VERSION>, and the special names last_green, last_rc and rolling work only against official releases, not forks. last_downstream_green has been removed in favour of last_green.
Where the Bazel binary comes from, and how to point it elsewhere
Downloads come from Google Cloud Storage by default, covering releases, release candidates and binaries built at green commits. The README states that downloaded artifacts are validated against the SHA256 value in BAZELISK_VERIFY_SHA256 when that variable is set in the configuration file. Two escape hatches exist. BAZELISK_BASE_URL replaces the release server: Bazelisk appends /<VERSION>/<FILENAME> to it and reads ~/.netrc for Basic authentication credentials. BAZELISK_FORMAT_URL goes further and replaces the URL format entirely, using placeholders %e for the extension suffix, %h for BAZELISK_VERIFY_SHA256 with its original casing, %m for the machine architecture, %o for the operating system and %v for the version. For a GitHub-hosted fork, the expected URL pattern is https://github.com/<FORK>/bazel/releases/download/<VERSION>/<FILENAME>, and the README advises following the same binary naming conventions used in bazelbuild/bazel so the URLs stay predictable. The practical constraint: a private mirror only works if the file names match what Bazelisk expects, or if you write a BAZELISK_FORMAT_URL that produces your own layout.
Installing Bazelisk and running a first build
Package managers install the wrapper under both names, bazelisk and bazel, so the same executable can stand in for the real binary. On macOS the README gives a single Homebrew command.
brew install bazeliskOn Windows there are three options, and each one puts bazelisk on PATH as both bazelisk and bazel.
winget install Bazel.Bazelisk
choco install bazelisk
scoop install bazeliskLinux has no package-manager line in the README. It directs you to the Releases page to download the binary and add it to PATH manually, which the README says also works on macOS and Windows. Frontend developers who prefer npm can install the published package instead.
npm install -g @bazel/bazeliskThe polyglot version manager mise is another supported route on Linux and macOS.
mise use -g bazelisk@latestOnce installed, the first real use is to pin a version in the repository and let the wrapper fetch it. Create a .bazelversion file in the workspace root containing a version label, then run any Bazel command through Bazelisk.
echo 7.0.0 > .bazelversion
bazelisk build //my:softwareBazelisk reads the file, downloads that release if it is not already cached, and passes build //my:software through to the real Bazel binary. The output you see is Bazel's own output, not the wrapper's. Running bazelisk version is the quickest way to confirm which Bazel release the current directory resolves to.
Limits, failure modes and when Bazelisk is the wrong layer
Bazelisk only downloads binaries that exist on the server it is pointed at. A Git commit hash is a valid version label, but the README notes that Bazel binaries are only available for commits that passed Bazel CI, so an arbitrary commit will not resolve. The special names last_green, last_rc and rolling are restricted to official releases and do not work with a fork. The fallback variable is a sharp edge: USE_BAZEL_FALLBACK_VERSION with the error: prefix turns a missing version into a hard failure, which is the behaviour you want on CI, while silent: quietly substitutes a version and hides the fact that the workspace did not pin one. Installing Bazelisk as bazel also creates a trap. Every tool, script or IDE plugin that shells out to bazel now goes through the wrapper, including ones that run outside the repository and therefore resolve a different version. The README itself flags this: a .bazelversion file only constrains people who use Bazelisk, and the note about ensuring developers install it points at exactly that gap. If your team builds a single project on a single Bazel release and manages that binary through a container image, Bazelisk adds a network fetch and a resolution order for no benefit.
Bazelisk against nvm, mise and a pinned container image
The README draws its own comparison: Bazelisk serves an analogous function for Bazel as nvm does for Node.js. The difference in approach is where the version lives. nvm stores a default per shell and switches Node versions through its own commands; Bazelisk reads the version from the repository, so the pin travels with the code and an upgrade becomes a normal pull request. That is also why the README suggests testing Bazel upgrades through a presubmit. mise overlaps more directly, since it manages many tools and the README lists mise use -g bazelisk@latest as a way to install Bazelisk itself; in that setup mise manages the launcher and Bazelisk manages Bazel. A container image takes the opposite approach: it bakes one Bazel binary into the image and pins the image tag. That is reproducible without a network fetch at build time, but it cannot serve a developer who has three repositories pinned to three different Bazel releases on one laptop, which is the case Bazelisk was built for.
Maintenance, upgrades and the Apache-2.0 licence
The repository is not archived, and the last push was on 2026-09-23. The most recent release listed is v1.29.0 from 2026-04-27, following v1.28.1 on 2026-01-19 and v1.28.0 on 2026-01-15, so releases are infrequent relative to commits. The Go module declares go 1.24.0 with toolchain go1.24.2 and depends on a small set of libraries: go-netrc for credentials, gofrs/flock, hashicorp/go-version for version parsing, mitchellh/go-homedir, golang.org/x/crypto and golang.org/x/term. Upgrading Bazelisk is a binary or package-manager swap, and it does not change the Bazel version your workspace uses, because that comes from .bazelversion, USE_BAZEL_VERSION or the fallback variable. The older Python implementation still works on any platform with a Python interpreter, but the README states it is unmaintained and supports fewer features. Bazelisk and the npm package are both licensed Apache-2.0. That licence permits commercial and private use and requires preservation of notices; it also includes a patent grant. This is a description of the licence text, not legal advice, so have your own counsel review it if you are redistributing the binary.
Editorial conclusion
Adopt Bazelisk if your repositories pin different Bazel versions in .bazelversion, or if you want a checked-in launcher that lets a newcomer build without installing Bazel first. Skip it if you build one project against one Bazel release and manage that binary with your own tooling, since the wrapper adds a download step and a resolution order you have to understand. Before rolling it out, verify what USE_BAZEL_VERSION and USE_BAZEL_FALLBACK_VERSION are set to on your CI machines, confirm which version the wrapper resolves by running bazelisk version in the workspace root, and check whether BAZELISK_BASE_URL or BAZELISK_FORMAT_URL is already set in your environment.
Frequently asked questions
What is Bazelisk?
Bazelisk is a wrapper for Bazel written in Go. It picks a Bazel version based on the current working directory, downloads it from the official server if needed, and passes all command-line arguments through to the real Bazel binary.
How do I install Bazelisk on Ubuntu?
The README gives no package-manager command for Linux. It directs you to the Releases page to download the Bazelisk binary and add it to PATH manually, which the README says also works on macOS and Windows.
How do I install Bazelisk on Windows?
The README lists winget install Bazel.Bazelisk, choco install bazelisk and scoop install bazelisk. Each one adds bazelisk to PATH as both bazelisk and bazel.
How do I install Bazel using Bazelisk?
You do not install Bazel separately. Bazelisk downloads the Bazel binary it resolves for the current directory and runs it, so installing Bazelisk as bazel in PATH is the documented approach.
How do I add Bazelisk to PATH?
The Homebrew, winget, Chocolatey and Scoop installs each add bazelisk to PATH as both bazelisk and bazel. On Linux the README says to download the binary from the Releases page and add it to PATH manually.
How do I use Bazelisk?
Call it the way you would call Bazel, for example bazelisk build //my:software. It resolves a version from USE_BAZEL_VERSION, .bazeliskrc or .bazelversion, downloads that Bazel release if required, and passes your arguments through to the real binary.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bazelbuild-bazelisk)