The Anatomy
Workspace, packages, labels, and Starlark
Read a Bazel repository with confidence: find the root, identify packages, understand labels, and scan BUILD files as declarations instead of scripts.

Level 0 teaches you how to enter a Bazel repository and understand what you are looking at. Before commands are useful, the checkout needs coordinates: where the repository starts, which package owns a file, how targets are named, and why a BUILD file is not an ordinary script.
Build The Repository Coordinates
0.1 Filesystem Hierarchy gives the physical map. Bazelisk can read
.bazelversion to select the requested Bazel version. Repository
markers define the root, BUILD files divide the tree into packages, and the
output tree keeps generated artifacts outside the source directories you edit.
0.2 Language of Labels turns that map into addresses. The same notation family shows up
in dependency lists, command-line target patterns, visibility rules, package
groups, and later query output. Once //pkg:target, :target, and //...
become coordinates instead of punctuation, many errors get easier to read.
0.3 Starlark Syntax Basics teaches the BUILD-file reading habit. The syntax may look Python-shaped, but the useful first pass is structural: what was loaded, which package defaults apply, which targets exist, and what their attributes mean.
Follow The Coordinates Into A BUILD File
Use one final repository fragment to combine the level's separate ideas:
demo/
├── MODULE.bazel
├── app/
│ ├── BUILD.bazel
│ ├── Main.java
│ └── settings.json
└── lib/
├── BUILD.bazel
└── Message.java
# //app/BUILD.bazel
load("@rules_java//java:defs.bzl", "java_binary")
java_binary(
name = "app",
srcs = ["Main.java"],
deps = ["//lib:message"],
data = ["settings.json"],
)
# //lib/BUILD.bazel
load("@rules_java//java:defs.bzl", "java_library")
java_library(
name = "message",
srcs = ["Message.java"],
visibility = ["//app:__pkg__"],
)
Before revealing the answer, identify the repository root, both packages, the
full label of each rule target, the dependency direction, and the distinct
roles of srcs, deps, and data. Then ask what would change if
app/config/BUILD.bazel were added around a file previously owned by //app.
Check the anatomy
MODULE.bazel marks the root. //app and //lib are packages because each has
a BUILD.bazel. Their rule targets are //app:app and //lib:message, and the
first may be shortened to //app. The dependency points from the application
to the library. Main.java and Message.java are direct build inputs in
srcs. //lib:message is a target dependency in deps. settings.json is a
runtime file in data. The library permits clients from exactly the //app
package. Adding a nested BUILD.bazel creates a new package: files beneath it
stop belonging to //app, so their labels and any parent globs or relative
references must follow the new boundary.
Finding the repository root and package boundary, expanding a canonical label, distinguishing files from rule targets, and reading a BUILD declaration structurally reveal the graph that later Bazel commands address.
Next: use those coordinates to build, test, run, and inspect targets in 1.1 CLI Survival Kit.