0.1 Filesystem Hierarchy
At first glance, a Bazel repository looks like an ordinary directory tree.
Bazel gives several files and paths in that tree specific roles: a repository
marker establishes the root, each BUILD.bazel creates a package, and
bazel-* symlinks provide access to generated outputs outside the source tree.
Bazelisk sits one step before that model: when a project uses it,
.bazelversion tells the launcher which Bazel binary should read the
repository.
One Tree, Four Roles
The four articles in this section answer different questions about the repository:
- 0.1.1 Bazelisk & .bazelversion explains how a project selects the Bazel version that
developers and CI run.
.bazelversionconfigures a compatible launcher; it does not define Bazel's repository structure. - 0.1.2 Repository Root shows how marker files such as
MODULE.bazelandREPO.bazelestablish the directory from which package names and labels are resolved. - 0.1.3 Package explains how
BUILD.bazelfiles partition the source tree. The nearest package boundary determines which package owns a file, and adding one can change file labels, recursiveglob()results, and the dependencies needed across packages. - 0.1.4 Output Root separates the sources you edit from Bazel-managed output. Convenience symlinks at the repository root make generated artifacts easier to find without turning them into source files.
Repository Structure Has Meaning
The central model is narrower than "every special file is a boundary." Within
the source tree, repository markers establish the coordinate system and
BUILD.bazel files divide that tree into packages. The labels in
0.2 Language of Labels attach to those packages, and the declarations in
0.3 Starlark Syntax Basics describe targets inside them.
.bazelversion and the output symlinks support that model without defining
package ownership. The former helps select the binary that runs Bazel; the
latter point from the checkout to generated state. Keeping those roles separate
makes it easier to tell whether a file affects launcher setup, repository
structure, package structure, or output navigation.
How To Read The Section
For the fastest orientation in an unfamiliar checkout, start with 0.1.2 Repository Root and 0.1.3 Package. They explain where Bazel's coordinates begin and how the source tree is partitioned. Read 0.1.1 Bazelisk & .bazelversion when you need to understand which Bazel release a command will run, and 0.1.4 Output Root after a build when you need to distinguish generated artifacts from sources.
Predict: //app:bundle includes config/settings.json through
glob(["**/*.json"]). A teammate adds app/config/BUILD.bazel without moving
settings.json or changing app/BUILD.bazel. What happens to the file's label
and to the parent package's glob?
Reveal
The new BUILD file makes app/config a separate package. The file's label
changes from //app:config/settings.json to
//app/config:settings.json, and the recursive glob in //app no longer
includes it.
The file stayed in the same directory, but its package ownership changed. If
//app:bundle still needs it, the new package must expose the file through a
target or exports_files(), and //app:bundle must refer to that cross-package
label.
A Bazel checkout combines four related but distinct roles: Bazelisk can select
the Bazel binary, repository markers establish the root, BUILD.bazel files
create packages, and output symlinks lead to generated state. Distinguishing
those roles gives labels and BUILD declarations a concrete filesystem context.
Sections in this chapter · 4
Version-aware Bazel launcher and project-pinned Bazel version.
Boundary marker files that define where one Bazel repository begins.
BUILD-file directories as package boundaries and file-ownership units.
Where Bazel writes generated outputs instead of modifying source directories.