aspect gazelle runs Gazelle (or aspect_gazelle_prebuilt, for Starlark-defined extensions) to generate and synchronize your repository’s BUILD files. On CI it detects whether BUILD files are out of sync with the source and fails the step if they are.
Run locally, aspect gazelle applies the fixes in place. --check-only defaults to auto: detect-only on CI, apply locally.
Setup: choosing a gazelle binary
aspect gazelle drives a Gazelle binary that you point it at with --gazelle-target (default //tools/gazelle:gazelle). Provide the binary either way below.
Prebuilt binary (recommended)
aspect_gazelle_prebuilt fetches a precompiled Gazelle binary from the aspect-gazelle releases. It needs no Go toolchain and no compile step, and it’s the only binary that can run Starlark/AXL extensions.
MODULE.bazel
tools/gazelle/BUILD.bazel
- No Go toolchain download and no first-run compile of the gazelle binary: developers fetch a cached prebuilt artifact instead.
- Runs Starlark/AXL extensions, so you can write generators without the Go extension API.
- Exposes prebuilt-only flags like
-progressand-cache(see Additional Gazelle flags). - Avoids the bootstrapping trap where a broken
BUILDfile referenced by your gazelle binary’sloadstatements stops gazelle from compiling, and so from fixing that file.
Building from source
Build Gazelle with the upstreamgazelle_binary macro from bazel-contrib/bazel-gazelle, composing whatever language extensions you need (including custom first-party Go extensions). This requires a Go toolchain.
tools/gazelle/BUILD.bazel
- Full control: compose any language extension and write custom generators against Gazelle’s Go
Languageinterface. - No dependency on which extensions ship in the prebuilt binary.
Incremental mode: only touch changed directories
On a large repo, running Gazelle over the whole tree on every change is slow.--scope=changed restricts it to directories that contain changed files:
aspect format, with the same --base-ref and --merge-base flags. --changed-file-pattern narrows which changed files count, for example to the languages your Gazelle plugins cover.
Escalation: some changes need a whole-repo run, and two things trigger one. By default a change to BUILD.bazel or MODULE.bazel escalates to --scope=all, because those files can affect dependency resolution across the repo. Change detection failing to resolve a base escalates too, with the same --merge-base=<sha> / --base-ref advice aspect format gives. Setting the patterns replaces the defaults, so include them if you want to keep them:
.aspect/config.axl
Watch mode
Pass--watch to keep BUILD files in sync while you edit. After the first run the task stays running, watches the Bazel workspace, and reruns Gazelle after each settled batch of file changes:
.git, .jj and Bazel’s convenience symlinks don’t trigger a rerun. Stop the task with Ctrl-C.
Without --watch, aspect gazelle runs once and exits.
How drift detection works
aspect gazelle always runs Gazelle with -mode=diff, whatever other flags you pass:
- Gazelle runs once with
-mode=diffand produces a unified diff without writing any files. - The task reads the diff to decide whether BUILD files are out of sync. It uses the diff output, not Gazelle’s exit code.
- With
--check-only=true(theautoresult on CI), a non-empty diff raises the--severityverdict. - With
--check-only=false(theautoresult locally), the task applies the diff withgit apply -p0.
Configuration
Gazelle target
.aspect/config.axl
Reacting to drift
auto, the default, is fail on a recognized CI host and info off it.
Additional Gazelle flags
Pass extra flags to the Gazelle binary. Any-mode flag is dropped, since the task controls the mode:
aspect_gazelle_prebuilt, such as -progress and -cache, fail against a from-source Gazelle binary.
To run a Gazelle subcommand, pass --gazelle-command=update or --gazelle-command=fix. With neither, Gazelle uses its own default. update-repos isn’t supported; run it with bazel run.
-index=lazy pairs well with --scope=changed for the best incremental performance: Gazelle only indexes the packages it visits rather than the whole repo.
Patch upload
When BUILD files are out of date on CI, the task uploads the diff as agazelle.patch artifact so developers can apply it locally. It’s on by default. To turn it off:
.aspect/config.axl
Options
It also takes the Bazel flag options common to every task that runs Bazel (
--bazel-flag, --bazel-startup-flag, --announce-bazel-*, --bes-backend, --bes-header); see aspect run.
CI example
.github/workflows/gazelle.yaml

