0.2 Language of Labels

The first time you read real BUILD files or Bazel commands, the notation can feel dense:

//app:server
:lib
//...
//friends:__subpackages__

Those forms look related because they are related, but they do not all do the same job. Some are ordinary labels naming one exact target. Some are local shorthand. Some are target patterns on the command line. Some are visibility specifications defining who may depend on whom. If 0.1 Filesystem Hierarchy teaches you how Bazel sees the repository tree, this section teaches you how Bazel names things inside it without treating every colon and slash as punctuation to memorize.

Labels Turn The Tree Into A Graph

Packages, files, and repositories only become navigable build objects once Bazel can name them. Ordinary labels are the core naming system. Bazel then reuses closely related syntax for selecting sets of targets and for describing package boundaries.

When a BUILD file says deps = ["//lib:core"], it names a target in Bazel's graph, not a filesystem path. In bazel test //..., the similar-looking form selects a set of targets rather than naming one target. In a visibility declaration, //app:__subpackages__ describes which client packages may cross a boundary. It is not a target you can build. The surrounding context tells you which job the notation is doing.

That is why this notation matters so early. Labels themselves show up in dependencies and load() statements, and close relatives of the same syntax show up in command-line selection, visibility rules, and later query output. Once you recognize that coordinate system, you can read BUILD-file strings as graph edges and boundaries with precise meaning.

One Notation Family, Four Jobs

One notation family serves four jobs.

  • 0.2.1 Label Anatomy introduces the full address form: repository, package, target. This is the anchor article for the whole section, because every shorthand and every special case is a variation on that structure.
  • 0.2.2 Syntactic Sugar & Relative Labels explains why Bazel code usually omits parts of the label when context already supplies them. This is where :lib, //pkg, and bare repository forms stop feeling cryptic.
  • 0.2.3 Target Patterns shifts from naming one target to selecting many. The syntax still resembles labels, but the job is different: //pkg:all, //pkg/..., and exclusions are CLI selection language, not target addresses.
  • 0.2.4 Visibility, 0.2.5 package_group, 0.2.6 package() Function, and 0.2.7 exports_files() turn the same general vocabulary toward boundaries and APIs. They answer "who is allowed to reach this target?" and "how do raw files cross package boundaries?"

Together, these forms connect repository structure, BUILD-file declarations, and the everyday commands you type.

Context Changes What The String Means

The difficulty is not that the rules are arbitrary. The difficulty is that similar-looking strings live in different contexts.

//app usually means the eponymous target //app:app, not "the package." But inside a package_group, //app does mean the package. //pkg/... looks like a path expression, but it is a target pattern. //visibility:public and //friends:__subpackages__ are written in label-shaped syntax, but they are visibility specifications, not ordinary targets you can build. Even the humble colon changes tone depending on where you are: :lib is a same-package shorthand in a BUILD file, while :all is a pattern operator on the command line.

Newcomers often think they are learning one rule and then keep hitting exceptions. A better way to see it is that Bazel reuses one coordinate style across adjacent problems. The surface notation stays similar because all of those problems are about addressing things in the build graph. What changes is the question being answered: one target, many targets, or allowed clients.

Start With The String You Cannot Read

If your main problem is "I keep seeing //foo:bar and do not know what part is what," start with 0.2.1 Label Anatomy and only then move to 0.2.2 Syntactic Sugar & Relative Labels. If the confusion comes from commands such as bazel test //... -//experimental/..., jump next to 0.2.3 Target Patterns. If what you really need is to understand package APIs and why Bazel is blocking one dependency, read 0.2.4 Visibility through 0.2.7 exports_files() as one cluster rather than isolated facts. Those articles together explain how labels become policy.

Do not chase every strange-looking label form immediately. At Level 0, the core forms are enough. Learn //pkg:target, :target, //..., and the basic visibility shapes first. The more exotic repository-name mechanics can wait until they solve a real problem for you.

key takeaway

Read label-shaped syntax by context: it may name one target, select a set of targets, or define an access boundary. Start with canonical label anatomy, then interpret shorthand, patterns, and visibility forms by the question they answer.