Bazel Reference

Kip Landergren

(Updated: )

My cheat sheet for Bazel covering useful resources and FAQs.

Contents

Installation

Use bazelisk, which is a:

brew install bazelisk

Note: on installation via homebrew, both bazelisk and bazel are added to $PATH resolving to the bazelisk binary.

Debugging

bazel build --sandbox_debug --verbose_failures //...

New Project Initialization

Bazel 8

echo "module(name = \"myproject\")" > ./MODULE.bazel

If using bazelisk:

echo '8.4.2' > ./.bazelversion

Commands

info
config
query query the build graph (specifically: the post-loading phase target graph, before options are evaluated)
cquery configurable query; query the build graph, taking into account select() and build options (specifically: the post-analysis configured target graph)
aquery action graph query; query for actions in the build graph (specifically: actions from the post-analysis configured target graph)

bazel info

bazel info execution_root

bazel config

bazel config <configuration key>

bazel build

bazel build //foo/bar:baz
bazel build //...

bazel clean

Remove Bazel-created outputs:

bazel clean

Remove the entire working tree created by a Bazel instance:

bazel clean --expunge

bazel help

bazel help [COMMAND]

bazel mod

bazel mod tidy

bazel query

Query all targets in workspace:

bazel query //...

Query all targets in my/package:

bazel query //my/package/...

bazel cquery

Executes a post-analysis dependency graph query. cquery essentially says “what does this target expression resolve to?”.

% bazel cquery 'deps(//:foo)'
Computing main repo mapping:
Loading:
Loading: 0 packages loaded
Analyzing: target //:foo (0 packages loaded, 0 targets configured)
INFO: Analyzed target //:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
//:foo (89f88d5)
@platforms//host:host (8d4a62c)
@bazel_tools//tools/genrule:genrule-setup.sh (null)
//:list.txt (null)
@bazel_tools//tools:host_platform (8d4a62c)
@platforms//os:osx (8d4a62c)
@platforms//cpu:x86_64 (8d4a62c)
@platforms//os:os (8d4a62c)
@platforms//cpu:cpu (8d4a62c)
INFO: Elapsed time: 0.143s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions

About the configuration identifiers:

//:foo (89f88d5) 89f88d5, the configuration identifier associated with the bazel command-line flags used for this target
@platforms//host:host (8d4a62c) 8d4a62c, the configuration identifier for platform resolution
@bazel_tools//tools/genrule:genrule-setup.sh (null) null configuration identifier because it is a source file
//:list.txt (null) null configuration identifier because it is a source file
@bazel_tools//tools:host_platform (8d4a62c) 8d4a62c
@platforms//os:osx (8d4a62c) 8d4a62c
@platforms//cpu:x86_64 (8d4a62c) 8d4a62c
@platforms//os:os (8d4a62c) 8d4a62c
@platforms//cpu:cpu (8d4a62c) 8d4a62c

bazel aquery

% bazel aquery //:foo
Computing main repo mapping:
Loading:
Loading: 0 packages loaded
Analyzing: target //:foo (0 packages loaded, 0 targets configured)
INFO: Analyzed target //:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
action 'Executing genrule //:foo'
  Mnemonic: Genrule
  Target: //:foo
  Configuration: darwin_x86_64-fastbuild
  Execution platform: @platforms//host:host
  ActionKey: 234f068ae935f30a82f3f9778cba12fceb572067fbe4b5cc64e790fbcaa64f5b
  Inputs: [external/bazel_tools/tools/genrule/genrule-setup.sh, list.txt]
  Outputs: [bazel-out/darwin_x86_64-fastbuild/bin/foo.txt]
  Environment: [PATH=/nix/store/93lxfa3hg9944zd0wsb2pvy20l9p0z1n-bash-interactive-5.3p9/bin:/nix/store/5m3k4f22kg542p2lr4ikk2xj6grlmvrg-coreutils-9.11/bin:/nix/store/i8ix8mqzcllzigx9dy046axn3g0w08cp-diffutils-3.12/bin:/nix/store/lnxqsqi2shcq5pidbbadljna7haasy55-file-5.47/bin:/nix/store/ix0a9p3m012l4d59w3g1lfsdx2azdn08-findutils-4.10.0/bin:/nix/store/nrjma0cjf0w66v99chkyayr3lh70q9yp-gawk-5.4.0/bin:/nix/store/b64rpqqkc7c53vd77g48g9hs0hy889s2-gnugrep-3.12/bin:/nix/store/lc3km2yx9pcw5qp5kb7v1pbp11g7n44j-patch-2.8/bin:/nix/store/cvkh602mhz8jyq4hnajkkm22xbyc3ndg-gnused-4.9/bin:/nix/store/9z132234zlrg0fgmsychpi86a762mmwi-gnutar-1.35/bin:/nix/store/cg0dga307n1m8m1hg7hkys3fw2hlxb7d-gzip-1.14/bin:/nix/store/fyyi8b1dpk3xpjnn52rznnpvlyivds97-python3-3.13.13/bin:/nix/store/zbara2rlmdaaf71hxxdq9qrwbx7jly9f-unzip-6.0/bin:/nix/store/vgcvcyndy12521f4p1wfxmz2scbc9852-which-2.23/bin:/nix/store/5yds4f92rf04ld4437x6nkbsbhbaiy7g-zip-3.0/bin]
  Command Line: (exec /nix/store/paxx0f0j7n247ydnkr5037zzhlw0g0sm-bash/bin/bash \
    -c \
    'source external/bazel_tools/tools/genrule/genrule-setup.sh; cat list.txt | grep foo > bazel-out/darwin_x86_64-fastbuild/bin/foo.txt')
# Configuration: 89f88d514ae4f10d9d870a8d4ad4febbb673599e129ca06fb95727563aa99bae
# Execution platform: @@platforms//host:host

INFO: Elapsed time: 0.247s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions

ActionKey identifies the action definition, not the contents of the input files. Note too that it appears to be after evaluation and variable expansion.

Same ActionKey (two ways to write the same variable):

    cmd = "cat $(<) | grep foo > $(@)",
    cmd = "cat $< | grep foo > $(@)",

Different ActionKey (extra space):

    cmd = "cat $(<) | grep foo > $(@)",
    cmd = "cat $(<)  | grep foo > $(@)",

bazel test

Run all test targets:

bazel test //...

Options

--subcommands -s print the full command prior to executing it

Make Variables

SRCS $(SRCS) the path names of the files corresponding to labels in the srcs list
< $(<) SRCS, if it is a single file

Note:

$(<) $< equivalent. single-character make variables do not need to be wrapped in parentheses

gazelle

bazel run //:gazelle

keep comments

foo_binary(
    # keep
    bar = "baz",
)
foo_binary(
    # keep: my comment explaining why we keep
    bar = "baz",
)

Rulesets

bazel-contrib/rules_go

bazel run @rules_go//go -- version
bazel run @rules_go//go -- mod tidy

aspect-build/rules_ts

aspect-build/rules_js

Use the bazel-managed pnpm:

bazel run @pnpm//:pnpm -- [OPTIONS, COMMAND, ARGS]

For a package at $PWD:

bazel run @pnpm//:pnpm -- --dir $PWD [OPTIONS, COMMAND, ARGS]

For the workspace root:

bazel run @pnpm//:pnpm -- --workspace-root [OPTIONS, COMMAND, ARGS]

Removing a package:

bazel run @pnpm//:pnpm -- --dir $PWD remove PACKAGE

Adding a new package:

bazel run @pnpm//:pnpm -- --dir $PWD add PACKAGE

or:

I have not had success getting:

bazel run @pnpm//:pnpm -- --workspace-root add --save-dev PACKAGE

to work.

More options and commands at pnpm reference doc.

rules_pkg

pkg_files

note: attribute prefix (AKA the installation directory) appears to be ignored if consumed by another pkg_files. pkg_filegroup will create the prefix.

possibly a bug as docs say:

pkg_files targets may be consumed by other pkg_files

and I don’t see any caveats about prefix.

pkg_filegroup

ibazel

brew install ibazel
ibazel --run_output_interactive=false run //:foo -- bar

Read from .bazel_fix_commands.json and do not prompt for restarting the ibazel process:

ibazel --run_output --run_output_interactive=false run //:foo -- bar

Terminology

@

Alias for the main repository.

action

The lowest level composable unit in the build system.

aquery (action query)

Command to query for actions in your build graph. operates on the post-analysis Configured Target Graph.

Related: cquery

attribute

A named parameter that controls how the rule behaves.

BUILD.bazel (BUILD file)

The main configuration file that tells Bazel what software outputs to build, what their dependencies are, and how to build them.

Related: package

boundary marker file

One of:

  • MODULE.bazel
  • REPO.bazel
  • WORKSPACE
  • WORKSPACE.bazel
cquery (configurable query)

Command to query over the configured target graph.

Related: aquery

dependency hell

The frustration from problems involved in managing software dependencies; Dependency hell Wikipedia article

Related: diamond dependency

diamond dependency

A problem where two dependencies have sub-dependency version conflicts.

Related: dependency hell, transitive dependency

direct dependency

Targets that are reachable through a path of length 1 in the build dependency graph.

Related: transitive dependency

incremental build

A build executed where only some dependencies are rebuilt.

Related: null build

library

A collection of code or data that can be imported.

module

Represents a target specifying a buildable unit.

Note: Sometimes used interchangeably with “target”.

Compare: target

null build

A build executed where the target and all its dependencies are already up to date.

Related: incremental build

package

The unit of code organization within a repository.

The set of targets defined by a BUILD file.

Identified by the BUILD file's relative path to the workspace root.

A container of targets.

Related: BUILD.bazel

repository cache

The content-addressed cache for the remote downloader.

rule

The definition of a series of actions and inputs.

target

A buildable unit of a workspace.

An object defined in a BUILD file.

Declared by instantiating a rule.

The “what” of what to build

Note: Someimtes used interchangeably with “module”.

transitive dependency

Targets that are reachable through a path of any length in the build dependency graph.

Related: direct dependency, diamond dependency

WORKSPACE file

File which identifies the directory and its contents as a Bazel workspace and lives at the root of the project's directory structure.

Related: workspace

workspace

A directory that holds your project's source files and Bazel's build outputs.

Related: WORKSPACE file

Frequently Asked Questions (FAQ)

How can I see the build graph?

bazel query 'deps(//:foo)' --output graph > graph.dot
dot -Tpng graph.dot -o graph.png

Can I generate a BUILD file as part of the build?

No because bazel needs all dependend-on files to exist during load time. Look into bazel-contrib/bazel-gazelle.

More info:

How do I specify which bazel version to use? How do I use different bazel versions per-project?

Via .bazelversion; e.g.:

$ cat .bazelversion
7.0.2

or through other means.

How do I pronounce “bzlmod”?

Possibly as: “BEE ZEE EL mod”

Why am I getting error: could not find common root of directories ?

Is it possible you have a symlink pointing outside the working directory?

I normally debug this by patching bazelbuild/bazel-watcher to get more info:

diff --git a/internal/ibazel/ibazel.go b/internal/ibazel/ibazel.go
index 9796b06..0a9ebac 100644
--- a/internal/ibazel/ibazel.go
+++ b/internal/ibazel/ibazel.go
@@ -616,6 +616,9 @@ func (i *IBazel) watchFiles(toWatch []string, watcher common.Watcher) {
        }

        watchList := keys(uniqueDirectories)
+
+       log.Errorf("Watching %d directories:\n  %s", len(watchList), strings.Join(watchList, "\n  "))
+
        err := watcher.UpdateAll(watchList)
        if err != nil {
                log.Errorf("Error(s) updating watch list:\n %v", err)

Resources