Bazel Starlark Rule Development Training
Master Starlark programming and custom Bazel rule development in 3 days. Build rules, providers, aspects, and transitions.
Become a Bazel rule author with this intensive 3-day training on Starlark programming and the rule development API. Learn to write custom rules, define providers for inter-target communication, build aspects for cross-cutting analysis, and implement transitions for multi-configuration builds. Master the skills needed to extend Bazel for any toolchain or workflow.
Training Details
| Duration | 3 days (24 hours) |
| Level | Advanced |
| Delivery | In-person, Live online, Hybrid |
| Certification | N/A |
Who Is This For?
- Build engineers developing custom Bazel rules for internal toolchains
- Platform engineers extending Bazel for proprietary languages or workflows
- Senior developers creating shared rule sets for their organization
- Open-source contributors building and maintaining Bazel rule repositories
- Build infrastructure teams designing extensible build abstractions
Learning Outcomes
After completing this training, participants will be able to:
- Write Starlark code fluently, understanding its restrictions compared to Python
- Develop custom rules with proper attribute schemas, actions, and outputs
- Define and propagate custom providers for type-safe inter-target data flow
- Implement aspects for cross-cutting dependency graph analysis
- Use transitions to change build configuration mid-graph
- Test rules using analysistest and Bazel's testing framework
Detailed Agenda
Day 1: Starlark Language and Rule Basics
Module 1: Starlark Language Deep Dive
- Starlark vs Python: no mutation after freeze, no recursion, no while loops, no global state
- Built-in types: strings, lists, tuples, dicts, structs, depsets
- depset: preorder, postorder, topological traversal for efficient transitive data
- .bzl file structure: load() statements, exported symbols, private functions
- String formatting, list comprehensions, conditional expressions
- Hands-on: Write Starlark utility functions, work with depsets, explore freeze semantics
Module 2: Macros — BUILD File Abstraction
- Legacy macros: Starlark functions called from BUILD files
- Macro expansion timing: loading phase, before analysis
- Macro limitations: no access to configuration, no provider propagation
- Debugging macros: print(), --output=build for expanded form
- Best practices: when to use macros vs rules
- Hands-on: Write macros that generate multiple targets, bundle common patterns, and reduce BUILD file boilerplate
Module 3: rule() Basics and Attributes
- rule() function signature: implementation, attrs, outputs, executable, test
- Attribute types: attr.label, attr.label_list, attr.string, attr.int, attr.bool, attr.string_list
- attr.label: allow_files, allow_single_file, providers, cfg, aspects
- mandatory, default, and doc parameters for attribute definitions
- Private attributes with underscore prefix for implicit dependencies
- Hands-on: Define a custom rule schema with typed attributes, mandatory fields, and default values
Module 4: Writing Your First Custom Rule
- Implementation function signature: def _impl(ctx)
- ctx object overview: ctx.attr, ctx.file, ctx.files, ctx.outputs, ctx.actions, ctx.label
- ctx.actions.declare_file() and ctx.actions.declare_directory()
- ctx.actions.run(): executable, arguments, inputs, outputs, mnemonic, progress_message
- Returning DefaultInfo with files, runfiles, and executable
- Hands-on: Build a complete text processing rule that reads input files, runs a tool, and produces output artifacts
Day 2: Actions, Providers, and Testing
Module 5: Actions Deep Dive
- ctx.actions.run(): argument construction with ctx.actions.args() for memory-efficient command lines
- ctx.actions.run_shell(): inline shell commands, tools attribute
- ctx.actions.write(): generating files from content or template substitution
- ctx.actions.symlink(): creating symlinks in the output tree
- ctx.actions.expand_template(): substitution-based file generation
- Action environment: env parameter, execution requirements, use_default_shell_env
- Hands-on: Implement a code generator rule using run(), write(), and expand_template() actions
Module 6: Providers — Inter-Target Communication
- DefaultInfo: files (default outputs), runfiles, data_runfiles, default_runfiles
- OutputGroupInfo: named output groups for --output_groups flag
- InstrumentedFilesInfo: code coverage integration
- Custom providers: provider() function, fields declaration
- Accessing providers: target[ProviderName], hasattr checks
- Provider propagation: returning multiple providers from implementation function
- Hands-on: Define custom providers for a compile-and-link toolchain, propagate metadata through the dependency graph
Module 7: Runfiles and Executable Rules
- Runfiles: ctx.runfiles(), collect_data, collect_default, symlinks, root_symlinks
- Merging runfiles from dependencies: runfiles.merge() and runfiles.merge_all()
- Executable rules: executable = True, ctx.outputs.executable
- ctx.actions.write() for launcher scripts
- Runfiles resolution at runtime: RUNFILES_DIR, RUNFILES_MANIFEST_FILE
- Hands-on: Build an executable rule that bundles data files, library dependencies, and a launcher script into a runnable target
Module 8: Testing Custom Rules
- analysistest framework: analysis_test(), make(), assert_equals
- Testing rule implementation: verifying providers, outputs, actions
- Testing failure cases: expect_failure in analysistest
- Testing macros: verifying expanded target graph
- Integration testing: sh_test wrapping bazel build/test commands
- Bazel's rules_testing library for provider assertions
- Hands-on: Write comprehensive tests for custom rules: positive tests, failure tests, provider assertions, and output verification
Day 3: Aspects, Transitions, and Publishing
Module 9: Aspects — Cross-Cutting Graph Analysis
- Aspect concept: visiting nodes in the dependency graph orthogonally to rules
- aspect() function: implementation, attr_aspects, attrs, required_providers
- Aspect implementation function: target and ctx parameters
- Propagation: attr_aspects specifying which attributes to follow
- Collecting information across the graph with providers and depsets
- Hands-on: Build a dependency license auditor aspect that traverses the build graph and collects license metadata from all transitive dependencies
Module 10: Transitions and Exec Groups
- Configuration transitions: changing --cpu, --compilation_mode mid-graph
- transition() function: implementation, inputs (reads settings), outputs (writes settings)
- Attribute transitions: cfg = transition for per-dependency configuration
- Outgoing edge transitions: cfg on attr.label and attr.label_list
- Rule transitions: cfg parameter on rule() for incoming transitions
- Exec groups: exec_groups parameter, ctx.actions.run(exec_group = "...")
- Hands-on: Implement a cross-compilation rule using transitions to build the same library for x86_64 and ARM64
Module 11: Symbolic Macros (Bazel 8+)
- Symbolic macros vs legacy macros: type safety, visibility, laziness
- macro() function: implementation, attrs, inherit_attrs
- Visibility semantics: macro-created targets and package visibility
- Lazy evaluation: symbolic macros evaluated only when targets are requested
- Migration from legacy macros to symbolic macros
- Hands-on: Convert legacy macros to symbolic macros, explore visibility differences and lazy evaluation behavior
Module 12: Publishing Rules and Capstone
- Rule repository structure: rules, toolchains, extensions, tests, examples, docs
- MODULE.bazel for rule repositories: module extensions, toolchain registration
- Documentation generation with Stardoc
- Semantic versioning for rule releases and compatibility_level
- Publishing to the Bazel Central Registry: presubmit.yml, source.json
- Hands-on: Capstone project — design and implement a complete custom rule set with rules, macros, providers, an aspect, documentation, tests, and MODULE.bazel integration ready for registry publication
Prerequisites
- Bazel Fundamentals and Multi-Language Build training or equivalent production experience
- Strong programming skills in Python (Starlark is Python-derived)
- Deep understanding of BUILD files, labels, and the Bazel dependency graph
- Familiarity with compilation toolchains and build artifacts
Delivery Formats
| Format | Description |
|---|---|
| In-Person | On-site at your company's location, hands-on with direct interaction |
| Live Online | Interactive virtual sessions with screen sharing and real-time labs |
| Hybrid | Combination of on-site and remote sessions, flexible scheduling |
All formats include hands-on labs, course materials, and post-training support.
Prerequisites
- Bazel Fundamentals and Multi-Language Build training or equivalent
- Strong programming skills in Python or similar language
Ready to get started?
Request a training quote for your team — in-person, live-online, or hybrid.