P.2.3 Core vs Rulesets
Bazel is a split system: a generic core understands dependency graphs, actions, caching, sandboxing, and execution, while rulesets teach that core how to build a particular language or workflow. That split makes the polyglot promise from P.1.1 Key Benefits concrete: the engine stays the same while the language support changes.1,2
"rust_binary")
rust_binary(
name = "app",
srcs = ["main.rs"],
)
What belongs to Bazel Core
The core owns build mechanics, not language semantics. In Bazel's artifact model, engineers declare what artifact they want and its dependencies. Bazel decides how to schedule the work, which actions can run in parallel, and which previous results can be reused safely.3 When a rule is implemented in Starlark, its implementation function still does not run the compiler directly during analysis. It registers actions, and the core executes those actions later only if their outputs are needed.2,4
That is why the same engine can support very different ecosystems. The core does not need special built-in knowledge for every compiler, package manager, or framework. It needs a stable model for targets, inputs, outputs, and actions.2,4
What rulesets add
Rulesets supply the language- or domain-specific part: rule symbols, attributes, tool integrations, and conventions. The natively shipped rules are only a small amount of core support. Starlark-defined rules are how Bazel adds support for languages and tools it does not ship natively.2 In practice, a good ruleset is more than a parser for srcs and deps: it also has to fit the expectations of a language community, including package-manager integration, IDE support, and toolchain configuration.1
This layer is broader than programming languages. The same extension model can also add package-manager bridges, code generators, linting, and other workflows that the core intentionally does not hardcode.1,2
Why this gives you one mental model
Once you see the split, the uniform CLI makes more sense. bazel build, bazel test, and dependency edges stay the same whether the repository contains Java, Go, Python, Rust, or a mixture of all of them.1,3 If a language is not supported out of the box, the answer is usually not to wait for core Bazel. You add or adopt a ruleset.1,2
For most users, this means you rarely need to think about the boundary day to day. You mostly consume rule symbols in BUILD files. Level 0 makes that concrete in 0.3.2 Rules and 0.3.5 Load Statements. Much later, 4.2 Custom Rules, Providers & Actions explains how to author new rules, while 4.6 Toolchains & Platform Resolution shows how rules declare the toolchains and execution constraints they need.
If Bazel feels like one tool for many languages, that is because the core is intentionally generic and the language knowledge lives in rulesets. Learn to read the rule surface first. The deeper mechanics of custom rules and toolchains can wait until later levels.
Why the boundary keeps getting sharper
Bazel is still moving more language behavior out of its historical Java core and into Starlark rules. For beginners, the resulting boundary is a smaller core and more independent rulesets.2 The same trend already shows up in migration guidance, where formerly builtin Java symbols such as java_common and JavaInfo move into rules_java, so extensions load them from rules packages rather than from the core binary.5
That detail matters more to rule authors than to beginners, but it reinforces the mental model: the smaller and more stable the core interface becomes, the easier it is for rulesets to evolve independently.2,5
Check your understanding · 3 questions
1.Match each layer of Bazel to what it is responsible for:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
2.Your language is not supported by Bazel out of the box. What is the usual answer?
Select one answer
3.True or false: what belongs to Bazel Core and what belongs to rulesets.
Choose True or False for each sentence
Footnotes
-
Bazel Vision — abstraction layer, multi-language support, and what a good ruleset must provide ↩1 ↩2 ↩3 ↩4 ↩5
-
Rules — native rules as core support, Starlark rules for languages and tools, and rule implementations registering actions during analysis ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Artifact-Based Build Systems — Bazel controls the how, schedules work from the dependency graph, and reuses results safely ↩1 ↩2
-
Extension Overview — loading, analysis, and execution phases, plus rules as the place where new language support is introduced ↩1 ↩2
-
Migrating to Bazel Modules (a.k.a. Bzlmod) - Maintaining Compatibility, Part 1 — formerly builtin Java symbols moving into
rules_javapackages ↩1 ↩2