0.3.2 Rules
After the file layout and declarative model from 0.3.1 Anatomy of a BUILD File, the next question is what those top-level calls actually are. java_library, cc_binary, and sh_test are rules: schemas for a kind of target. Calling one in a BUILD file instantiates a rule target with a label, attributes, and hidden implementation logic that Bazel later uses to produce artifacts and dependency information.1,2,3
Rule Is A Type, Target Is An Instance
A real example appears in app/BUILD.bazel:
java_binary(
name = "server",
srcs = ["Main.java"],
deps = [":lib"],
)
In that snippet, java_binary is the rule. server is the target name. Together with the package path //app, that declaration becomes the label //app:server.1,2,4 A rule is not the same thing as a rule target, even though people sometimes use the words loosely.4
That distinction matters because labels from 0.2.1 Label Anatomy point at targets, not at rule types. A BUILD file is therefore mostly a list of instantiated rule types: each call creates one target that other targets can depend on later.2,4
What A Rule Contributes
A rule does two jobs. First, it defines the attribute schema available in the call: which fields exist, and what kind of information they accept. Second, it hides the build logic that turns those attribute values into outputs and metadata for downstream targets.1,3,4
For a BUILD-file author, that means you do not spell out compiler invocations or file-copy steps in the BUILD file. You fill in facts such as name, source files, and dependencies, and the rule implementation handles the mechanics.1,4 That is also why 0.3.3 Attributes & Semantic Roles deserves its own article: the meaning of srcs, deps, data, or rule-specific fields comes from the rule kind you are calling.
Rule Families Help You Read Intent
Most rules come in recognizable families. A common pattern spans *_library, *_binary, and *_test: libraries are separately compiled modules, binaries are executable programs, and tests are specialized executables for automated verification.2 When you see those names in a BUILD file, you can already make a good first guess about how the target is meant to be used.
That naming pattern also explains why a java_binary is something you may later run with 1.1.2 bazel run & Runfiles, while a java_library is usually something other targets depend on. The prefix often signals the language or ruleset: cc_* for C++, java_* for Java, and many others supplied by external rulesets rather than Bazel core itself.1,2,4 P.2.3 Core vs Rulesets explains the bigger split between the generic engine and language plugins. 0.3.5 Load Statements shows how rule symbols enter a BUILD file.
Why Some Old BUILD Files Have Fewer load() Lines
The direction of modern Bazel is to make rule origins explicit and uniform: if a BUILD file uses a rule symbol from a ruleset, it should load that symbol near the top of the file. That makes the file's vocabulary visible before the target declarations begin, which is the main beginner-level habit to build before 0.3.5 Load Statements.
Older Bazel versions have a historical quirk: some language rules were available without an explicit load() because they shipped through Bazel's built-in surface. Bazel 8 started the transition with automatic loading to give projects time to migrate, and Bazel 9 disables that autoloading so rules come from their own repositories explicitly.5,6 If you read an older example that calls cc_library or java_library without a matching load(), treat that as compatibility history, not the pattern to copy into new material.
Not Every Target Is A Rule Target
Not every label in Bazel names a rule target. The official terminology separates rule targets from file targets, and also treats package_group as its own target kind used mainly for visibility control.3,4 //app:server is a rule target, //app:Main.java is a file target, and a package_group target exists to be referenced from visibility settings rather than to compile code.3
The distinction prevents a common beginner mistake when reading BUILD files: assuming that every target is "some rule invocation." Rules are the most important target kind in everyday BUILD-file reading, but they are still just one category inside the broader target model.3,4
A rule is the type. A rule target is the instance created by calling that type in a BUILD file. When you open an unfamiliar package, first identify the rule families in use, then read each call as "one target of this kind with these attributes." The next step is 0.3.3 Attributes & Semantic Roles, where those fields get their semantic roles. Defining brand-new rule types waits until 4.2 Custom Rules, Providers & Actions.
Check your understanding · 2 questions
1.Match each rule family to its typical role in a Bazel build:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
2.True or false: rules, targets, and target kinds.
Choose True or False for each sentence
rule and rule target are not the same thing. Calling java_library creates a rule target.rule target is the type. rule is one use of that type in a BUILD file.Footnotes
-
Bazel Training 101 (Part 9): Packages, Rules, Targets, and Labels — rule as schema and black box, constructor-like rule calls, naming families, and common BUILD-file attributes ↩1 ↩2 ↩3 ↩4 ↩5
-
BUILD files — rule calls creating targets, common
*_library/*_binary/*_testfamilies, and BUILD-file rule semantics ↩1 ↩2 ↩3 ↩4 ↩5 -
Repositories, workspaces, packages, and targets — rule instances as input/output relationships, and the distinction between rule, file, and package-group targets ↩1 ↩2 ↩3 ↩4 ↩5
-
Bazel Glossary — precise terminology for rule vs rule target, target kinds, native rules, and attribute schema ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Bazel 8.0 LTS Release Blog Post —
--incompatible_autoload_externally, modularized rulesets, and the migration toward explicit load statements before Bazel 9 ↩ -
BazelCon 2025 Day 1: State of the Union — Starlarkification status, rule sets in their own repositories, and Bazel 9 disabling autoload ↩