0.2.1 Label Anatomy

Every Bazel library, binary, test, and source file has an address called a label. Labels are how BUILD files declare dependencies, how the command line specifies what to build, and how Bazel's query tools navigate the dependency graph. To start, get comfortable with the common explicit apparent form1:

@repo_name//path/to/package:target_name

The form has three components separated by fixed delimiters: the repository, the package, and the target.

The single-@ repository name is apparent: it is the name visible from the repository where the label is written. Bazel's canonical form begins with @@ and uses a unique resolved repository name. You will usually write apparent labels. The distinction matters when inspecting resolved external dependencies.1

What does this Bazel label identify?
Each colored part answers one question
EXPLICIT APPARENT LABEL
@rules_cc // cc/toolchains : compiler
REPOSITORY
Which repository?
Name visible from here
@rules_cc
PACKAGE
Which Bazel package?
Directory with a BUILD file
cc/toolchains
TARGET
Which declared item?
A rule target or file target
compiler
EXPLICIT APPARENT LABEL
@rules_cc//cc/toolchains:compiler
@rules_cc
REPOSITORY
Which repository?
Name visible from here
cc/toolchains
PACKAGE
Which Bazel package?
Directory with a BUILD file
compiler
TARGET
Which declared item?
A rule target or file target
One @ means apparent: the repository name as it is visible from the current repository. A canonical label starts with @@ and uses Bazel's unique resolved repository name.

The Three Components

@repo_name — The Repository

The first component identifies which repository the target lives in1. The repository concept maps to the directory tree anchored by a Bazel boundary marker, as described in 0.1.2 Repository Root.

Your project is the main repository. External dependencies pulled in via bazel_dep() in MODULE.bazel are also repositories, each fetched on demand into a location Bazel manages2. When referring to a target in the current repository, the @repo_name part is omitted entirely1:

//app:server

This is the form you'll see most often in your main repository. The leading // signals "start from the root of the current repository". The same shorthand also works from files evaluated inside an external repository.

When referring to a target in an external repository, the @ prefix and the repository name are required:

@rules_cc//cc:defs.bzl

//path/to/package — The Package

The second component is the package name, which is the path from the repository root to the directory containing the BUILD file1. This is the same concept as the package from 0.1.3 Package: the directory where a BUILD.bazel (or BUILD) file lives defines a package, and the directory's path relative to the root becomes the package's name.

For a BUILD.bazel file at app/backend/BUILD.bazel, the package component is //app/backend.

:target_name — The Target

The third component names a specific target within the package1. A target is anything declared in a BUILD file. For example, a rule invocation like cc_binary(name = "server", ...) creates a target named server. Source files in the package directory are also targets, referenced by their path relative to the BUILD file3:

//app:main.cc

The name attribute of a rule call defines the target name1. That name is local to the package, so two packages can each have a target named lib without conflict because the full label includes the package path.

What a Label Can Point To

Labels mostly address two kinds of targets2:

  • Rule targets — created by calling a rule in a BUILD file (cc_binary, java_library, sh_test). These represent buildable units: something Bazel knows how to compile, link, test, or otherwise produce.
  • File targets — files owned by a package. Source files exist in the repository. Generated files, also called derived or output files, are produced by rules.2

Both are valid label references. //app:server might point to a cc_binary rule target, while //app:main.cc points to a source file in the same package. Bazel resolves the label the same way regardless of what it points to2. The next item, 0.2.2 Syntactic Sugar & Relative Labels, explains why those labels are often shortened in real BUILD files.

Targets Are Not Paths

A label names something in Bazel's target namespace, not an arbitrary path on disk. A file target corresponds to one actual file, but a rule target may correspond to zero, one, or many files. Some files on disk are deliberately hidden implementation details and have no label you can write in a BUILD file or on the command line.4

That is why rule outputs can be surprising at first. Some rules create first-class output file targets in the same package as the rule. For example, declaring java_binary(name = "foo", ...) also implicitly declares an output file target named foo_deploy.jar. Bazel can build it on demand, other targets can depend on it when the rule contract allows that, and query tools can observe it.4 Other generated files, such as low-level object files produced during compilation, are just internal artifacts. They may exist under Bazel's output tree, but they are not public target names.4

When writing a dependency, command-line target, or query expression, think in labels first and filesystem paths second. The rule-authoring version of this distinction appears later in 4.2.1 Rule Function, where custom rules decide which generated files become part of the target's public contract.

Putting It Together

Given this directory tree:

my-project/
├── MODULE.bazel
├── app/
│   ├── BUILD.bazel
│   ├── main.cc
│   └── server.cc
└── lib/
    ├── BUILD.bazel
    └── utils.cc

The labels for targets in this project:

TargetLabel
A cc_binary named server in app/BUILD.bazel//app:server
The source file main.cc//app:main.cc
A cc_library named utils in lib/BUILD.bazel//lib:utils

Dependencies between packages use these labels. The app/BUILD.bazel might declare:

cc_binary(
    name = "server",
    srcs = ["main.cc", "server.cc"],
    deps = ["//lib:utils"],
)

deps = ["//lib:utils"] is a label reference. It tells Bazel that building //app:server requires first building //lib:utils.

File Labels in Subdirectories

When a source file lives in a subdirectory of the package (a subdirectory without its own BUILD file), the label uses the path relative to the BUILD file's directory1:

//my/app:testdata/input.txt

This is the file my/app/testdata/input.txt, owned by the package my/app because testdata/ has no BUILD file of its own (as covered in 0.1.3 Package).

A common mistake is trying to use a relative path to refer to a file in a different package. If testdata/ has its own BUILD file, it's a separate package, and the correct label is //my/app/testdata:input.txt, not testdata/input.txt1.

Reproduce the distinction between a valid label shape and a missing target with the //lib:missing alias.

key takeaway

A label is the address of any target in the build graph. In the common @repo//package:target form, @repo identifies the repository, the package maps to a directory with a BUILD file, and the target names a specific rule or file there. Omit @repo for the current repository. //app:server is the form you will use most in the main repository. Bzlmod's repository-name mapping belongs to 3.1.3 Repo Mapping.

Check your understanding · 3 questions

1.Match each component of the label @rules_cc//cc:defs.bzl to its role:

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

Answers
@rules_cc
//cc
:defs.bzl

2.True or false: label addressing and Bazel terminology.

Choose True or False for each sentence

For targets in the current repository, the @repo_name part may be omitted — //pkg:target is the normal form.
A source file like main.cc in the app/ package is addressable as //app:main.cc.
A label names a target in Bazel's graph, not an arbitrary filesystem path.
Two packages can each declare a target named lib without conflict, because the full label includes the package path.

3.A file lives at my/app/testdata/input.txt, and testdata/ has no BUILD file of its own. Which label is correct?

Select one answer

0 of 3 answered

Footnotes

  1. Labels — Full label anatomy, package and target name components, shorthand forms, file labels in subdirectories, cross-package reference rules 1 2 3 4 5 6 7 8 9

  2. Repositories, workspaces, packages, and targets — Target types (source files, generated files, rules), package groups, file-to-package ownership 1 2 3 4

  3. Packages, Rules, Targets, and Labels — Label syntax @repo//pkg:target, shorthand conventions, canonical vs apparent names are internal-only

  4. Common definitions — Implicit output targets, target namespace vs filesystem namespace, and hidden generated implementation files 1 2 3