0.1.4 Output Root

After your first bazel build, Bazel normally creates convenience symlinks at a writable repository root. They point into its output directory hierarchy1, and their names or presence can be configured. Bazel keeps build artifacts outside the source tree2, and the symlinks provide quick access to find them.

The Convenience Symlinks

With the default symlink prefix, four symlinks normally appear alongside MODULE.bazel (0.1.2 Repository Root) and your BUILD.bazel files1:

my-project/
├── MODULE.bazel
├── BUILD.bazel
├── app/
│   ├── BUILD.bazel
│   └── main.cc
├── bazel-bin → ...            ← compiled outputs
├── bazel-my-project → ...     ← execution root
├── bazel-out → ...            ← configuration output tree
└── bazel-testlogs → ...       ← test logs
SymlinkContents
bazel-bin/Compiled binaries, libraries, and generated files for the current build configuration.
bazel-my-project/The execution root — the working directory where build actions run. Named after the project directory.
bazel-testlogs/Test logs and results (test.log, test.xml) for the current configuration.
bazel-out/The output path containing configuration-specific subtrees for this repository. bazel-bin is a shortcut into one configuration's bin/ directory inside it.

Bazel does not use these convenience symlinks internally1. Their destinations are Bazel-managed state outside your source tree.

Path Mirroring

Output paths mirror the package structure (0.1.3 Package): the package part of the label becomes the subdirectory under Bazel's output trees. Most targets have one main output location. Tests are the common exception: Bazel builds the test program under bazel-bin/, then writes execution artifacts such as logs and XML under bazel-testlogs/1.

The diagram below shows one runnable example, reproduced by the output-path-mirroring snippet. The sample files are representative, not exhaustive: real output directories often include helper files such as params files or test metadata.

Where did my build or test output go?
Start with the label: its package path usually appears under Bazel's output shortcuts
Label
Outputs
//app:server
C++ binary
Build artifact
bazel-bin/app/server
//lib/util:helpers
Java library
Build artifact
bazel-bin/lib/util/libhelpers.jar
//tests/api:api_test
C++ test
Build artifact
bazel-bin/tests/api/api_test
Test run artifacts dir
bazel-testlogs/tests/api/api_test/
Sample files
test.log · test.xml
These are examples, not a stable path API. Exact files depend on the rule and configuration, and bazel-bin / bazel-testlogs are convenience symlinks.

One test target can have a built test executable in bazel-bin/ and a separate per-target artifact directory in bazel-testlogs/1, so "one label -> one final file" does not describe tests.

Configurations Inside bazel-out

Inside bazel-out/, Bazel creates a subdirectory for each build configuration — a combination of target platform, compilation mode, and other settings1:

bazel-out/
├── k8-fastbuild/
│   ├── bin/                ← compiled outputs (BINDIR)
│   └── testlogs/           ← test results
├── k8-opt/
│   ├── bin/
│   └── testlogs/
└── _tmp/
    └── actions/            ← stdout/stderr from build actions

The bazel-bin and bazel-testlogs symlinks point to one configuration at a time: the configuration of your most recent top-level build or test. Change flags such as -c opt, build for a different platform, or switch to a top-level target with a different configuration, and those symlinks may point somewhere else. Older outputs still remain in bazel-out/.

If you need the full picture, look in bazel-out/. It keeps one subtree per configuration, while bazel-bin and bazel-testlogs are just shortcuts into one of them.

Why Outputs Live Outside the Source Tree

Keeping generated state separate prevents outputs from masquerading as inputs and lets several configurations coexist without overwriting source files3. Edit files under the repository tree, but treat bazel-* entries as generated views managed by Bazel.

When you need an exact managed path, ask Bazel with the commands in 1.1.7 bazel info. Before deleting generated state, read 1.1.6 bazel clean to see what the cleanup commands actually remove. You do not need to understand the action cache or server lifecycle just to find a freshly built artifact.

Gitignoring Output Directories

The convenience symlinks should be excluded from version control:

/bazel-*

This catches all four convenience symlinks: bazel-bin, bazel-out, bazel-testlogs, and bazel-<project-name>1.

key takeaway

Bazel keeps generated outputs outside your source tree and exposes convenience symlinks (bazel-bin, bazel-out, bazel-testlogs, bazel-<project-name>) at the repository root. Package paths mirror into the output trees, so a label helps predict where to look. bazel-bin holds built outputs for the active configuration, while test execution artifacts appear under bazel-testlogs. Treat every /bazel-* entry as generated state and keep it out of version control.

Check your understanding · 2 questions

1.Match each convenience symlink to what it points at:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
bazel-bin/
bazel-testlogs/
bazel-out/
bazel-<project-name>/

2.True or false: how Bazel manages output directories.

Choose True or False for each sentence

Bazel writes compiled outputs directly into the source tree for easy access.
The bazel-bin symlink may point to a different subdirectory after rebuilding with different flags.
The path under bazel-bin mirrors the target's package path.
The bazel-* convenience symlinks should be committed so every clone sees the same outputs.
0 of 2 answered

Footnotes

  1. Output Directory Layout — Convenience symlinks, layout diagram, and configuration directory structure 1 2 3 4 5 6 7

  2. Bazel 101 Training (Part 6): Create a repository — Bazel never writes outputs into the source tree

  3. Output Directory Layout — separation of source and generated state and configuration-specific output trees