Skip to main content
You can install the Aspect CLI using several methods. All of them install the aspect-launcher, a small binary added to your PATH as aspect. This launcher downloads and runs the version of the Aspect CLI binary configured in your repository. It operates similarly to how bazelisk fetches the configured version of Bazel, or how nvm or n- manages Node.js versions. Find the latest releases at https://github.com/aspect-build/aspect-cli/releases.
After installing, follow the Quickstart for a 10-minute end-to-end walkthrough: build, test, customize built-ins, and extend the CLI with your first custom task.

Install with curl

The curl script works on macOS and Linux without any prerequisite package manager. Run:
This installs the aspect-launcher binary as aspect on your PATH.

Updating with curl

To update the aspect-launcher with curl, re-run the installation script:

Install with Homebrew (macOS)

To install via Homebrew, run the following command:
Alternatively, tap the repository first and then install:
This installs the aspect-launcher binary as aspect on your PATH.

Updating with Homebrew (macOS)

To update the aspect-launcher with Homebrew, run the following commands:

Install the Aspect CLI with direnv and multitool

This method assumes your development environment uses bazel_env.bzl. For examples, refer to the aspect-starters repositories on GitHub.
  1. Add aspect to the multitool lockfile, as shown in this example.
  2. Build and run your bazel_env target. Bazel will handle the installation of aspect, making it available on your PATH.
For more details on this pattern, watch the Aspect Insights podcast episode “Developer Tooling in Monorepos with bazel_env”:

Install with GitHub Actions

Use the aspect-build/setup-aspect action. It installs the launcher, installs Bazelisk (unless bazel is already on PATH), wires --disk_cache / --repository_cache to the GHA cache, and exchanges your ASPECT_API_TOKEN for a short-lived JWT, all in one step. The same one-liner works on provider-hosted runners (ubuntu-latest, macos-latest) and on Aspect Workflows CI runners.
Pin to a full-length commit SHA (with the version annotated in a trailing comment) per GitHub’s third-party action security guidance. Find the SHA for the latest release on the setup-aspect releases page, each release’s notes carry a copy-paste snippet. The CLI version itself is pinned by your repo’s .aspect/version.axl (see version pinning), the launcher reads that file and downloads the matching CLI on first aspect invocation, so local and CI stay in sync without bumping a launcher version in your workflow YAML.

Without setup-aspect

If for some reason you’d rather install the launcher inline (or you’re on a CI provider without an equivalent action, Buildkite, GitLab, CircleCI), the curl one-liner works:
You give up GHA caching, the API-token-to-JWT exchange, and the Bazelisk install, all of which setup-aspect does for you.

Install the Aspect CLI manually from GitHub

Visit the Aspect CLI Releases page on GitHub to download the appropriate binary for your platform, such as aspect-launcher-aarch64-apple-darwin for macOS arm64, or equivalents for other architectures and operating systems.

macOS example

  1. Download the aspect-launcher-aarch64-apple-darwin binary from the Aspect CLI Releases page.
  2. In your terminal, run these commands to clear the untrusted developer attribute, make the binary executable, and move it to your PATH:

Keep your team typing bazel with the tools/bazel wrapper

A common objection when adopting the Aspect CLI is “we don’t want to teach our developers a new command name.” You don’t have to. Drop a tools/bazel shell wrapper into your workspace and Bazelisk will exec it on every bazel invocation, routing each command to the right tool: aspect for the verbs aspect wraps (build, test, lint, format, gazelle, buildifier, delivery, any custom .axl task), vanilla bazel for everything else (query, info, clean, …). Your arguments are forwarded verbatim. The wrapper never inspects or rewrites a flag, it only picks which binary to exec, and aspect passes the flags it doesn’t recognize through to Bazel in the slot you typed them in.
Requires Bazelisk. The tools/bazel hook is a Bazelisk feature, the real bazel binary does not look for it. This works if the bazel on your team’s PATH is Bazelisk, which is the most common setup (every Bazelisk release since 2019 honors the hook).
bazel run is deliberately left on vanilla bazel: aspect run exists, but its semantics don’t line up closely enough with bazel run to shadow it transparently yet. Reach for aspect run directly when you want it, or add run to the verb list below once you’ve validated it for your workflows. The Aspect CLI can drop the wrapper in for you. From anywhere in your workspace:
This downloads the wrapper and its reference doc at a pinned release tag (not main), writes tools/bazel (executable) and tools/bazel.md, and prints optional rc snippets for your shell that turn the escape hatches below on and off. Pin a specific version with --version=<tag>. Re-running is idempotent: an up-to-date copy is left untouched, a newer release is offered as an upgrade. In CI, aspect setup tools-bazel-wrapper --check exits non-zero when tools/bazel is missing or stale so you can gate on it. aspect setup tools-bazel-wrapper --uninstall removes the files again.
Requires Aspect CLI v2026.38.14 or newer, which is where this command landed. On an older release, install the wrapper by hand instead, as shown next.
Or drop it in by hand:
Developers who prefer raw bazel for a shell session can set ASPECT_WRAPPER_SKIP=1 to bypass routing entirely.

Customize the verb routing

Two lists at the top of tools/bazel drive every routing decision. Edit them in your repo’s copy:
  • ASPECT_VERBS — the verbs routed to aspect. A verb in neither list is treated as a custom .axl task and also routes to aspect, so what listing one really buys is the fallback to vanilla bazel when aspect isn’t installed. That only makes sense for verbs Bazel also has.
  • BAZEL_VERBS — the closed set of Bazel commands. A verb here that is not in ASPECT_VERBS goes to vanilla bazel untouched (query, info, clean, mod, coverage, …). Update it only when Bazel adds a command.
Two common edits:
  • Send build / test to vanilla bazel instead. Remove them from ASPECT_VERBS and they fall through to the real bazel untouched. Keep the aspect-only verbs (lint, format, delivery, gazelle) listed so bazel lint and friends still reach aspect. Useful when your team wants bazel build to stay pure-Bazel but still pick up aspect for the verbs Bazel doesn’t have.
  • Add run, or your own aspect commands. Once aspect run suits your workflows, add run to ASPECT_VERBS so bazel run routes through it.
The full reference (routing rules, every escape hatch, the trace output, and how the wrapper avoids recursing back into aspect) lives next to the script: tools/bazel.md.