Skip to main content
Bazel has its own vocabulary for describing code structure. This guide explains the four core concepts you’ll use every day: packages, rules, targets, and labels.

Packages

Bazel uses files named BUILD (or BUILD.bazel) to describe the source files which may be built or tested. Any directory containing a BUILD file is called a “package” in Bazel. This includes subdirectories unless they have their own BUILD file.

Package encapsulation

Bazel packages are isolated units with well-defined boundaries:
  • glob stays within the package. It is a function wildcard patterns for filenames such as **/*.txt.
  • Source files are “owned” by their package and aren’t visible outside, unless exposed with exports_files.
  • Output files are always written to the bazel-out folder within the same package.

Rules

Bazel defines a rule as a schema for defining rule targets in a BUILD file, such as sh_library. From the perspective of a BUILD file author, a rule consists of:
  • A set of attributes and,
  • A black box logic which tells the rule target how to produce output  artifacts and pass information to other rule targets.
Rules are provided by “rulesets”, which are Bazel plugins loaded from the MODULE.bazel file, such as rules_shell. You may think of a rule as a factory function or a constructor. Call it from BUILD to describe your sources. The result is a type of target called a “rule target”.

Rule Naming Convention

A rule is generally designed to be used with a particular bazel command, making it buildable, runnable, and/or testable. A naming convention typically hints which one it is:
Unlike other build systems, most rules do not allow you to give procedural logic for what to do, that’s the job of the rule implementation logic. Rules only describe the source files and their dependencies.

Rule example

The arguments to this sh_binary rule are called “attributes”. Common attributes across most rules include:
  • name is always required. Use this in a label to refer to the target
  • srcs typically means files in the source tree
  • deps typically means other rule targets which are needed at build time
  • data is like deps but is only needed at runtime
Other attributes are particular to the rule implementation.
  • env is an attribute present on all executable targets, providing environment variables when the target is executed with bazel run

Targets

Not all targets are created from rules, there are a few other types of target:
  1. Source files: refer to an individual file in the source tree.
  2. Build output files (so long as they are pre-declared).
  3. Package groups, which are useful with Bazel’s visibility feature.

Target Patterns

On the command-line, you may want to refer to groups of targets. There are some special syntax:
  • :all or :* means “all targets in this package”
  • ... means “all targets recursively in this package and subpackages”
  • //... means “all targets in this repository”

Labels

Labels are the way to reference a target from the command-line or in a BUILD file. Think of labels like a URL for a target.

Label syntax

Sometimes you might see a label starting with a double-@ sign. This is a “canonical” repository name, and you should not need to use it. This is a way to bypass the visibility restriction, but the name of the resulting repositories is brittle and hard to predict.

Label shorthand

If the working directory is in the same repository, //my_library/util:draw_circle
  • // means the root of that repository.
  • On the command line, labels can be relative to the working directory
  • Each package has a default label, named after the package
You can usually use this shorthand to save typing. For example you could just cd backend; bazel run devserver rather than bazel run //backend/devserver:devserver. Every package should have a thoughtfully chosen default target, to save typing and make an ergonomic experience for developers interacting with Bazel in your project. You can use alias to introduce an indirection, for example if you’d like users to be able to bazel run backend from the repository root, then you add an alias:
You can get a reminder of the syntax with bazel help target-syntax