Starlark Configuration
bz uses Starlark, a Python-like language designed for configuration. If you’ve written Bazel BUILD files, you already know Starlark.
Why Starlark?
- Familiar syntax - Python-like, easy to learn
- Deterministic - No side effects, reproducible configs
- Composable - Load and reuse configuration snippets
- Type-safe - Catches errors early
Basic Syntax
Variables
# Stringsname = "rules_go"url = "https://bcr.bazel.build"
# Numberscount = 5timeout = 30
# Booleansverbose = Truedry_run = False
# Listsmodules = ["rules_go", "rules_python", "gazelle"]
# Dictionariesoptions = { "timeout": 30, "retries": 3,}Functions
# Calling functionsbcr = registry.http("https://bcr.bazel.build")
# Named argumentssync.workflow( name = "my-workflow", origin = bcr, destination = mirror, modules = ["rules_go"],)Conditionals
env_name = env("ENVIRONMENT")if env_name == "production": registry_url = "https://prod-registry.example.com"else: registry_url = "https://dev-registry.example.com"List Comprehensions
# Generate module listprefixes = ["rules_", "bazel_"]modules = [p + "go" for p in prefixes]# Result: ["rules_go", "bazel_go"]Environment Variables
Use env() to read environment variables:
# Read required variabletoken = env("GITHUB_TOKEN")
# With default valueregistry = env("REGISTRY_URL") or "https://bcr.bazel.build"Complete Example
# bz.star - Complete configuration example
# Define registriesbcr = registry.http("https://bcr.bazel.build")
# Local mirror for developmentlocal_mirror = registry.file("./bazel-registry")
# Git repository for team sharingteam_registry = registry.git( url = "https://github.com/myorg/bazel-registry.git", branch = "main",)
# Production HTTP serverprod_server = registry.http_put( url = "https://registry.example.com", auth = auth.bearer(token = env("REGISTRY_TOKEN")),)
# Modules to synccore_modules = [ "rules_go", "rules_python", "rules_rust", "gazelle",]
build_modules = [ "bazel_skylib", "platforms", "rules_cc",]
# Development workflow - sync to localsync.workflow( name = "dev", origin = bcr, destination = local_mirror, modules = core_modules + build_modules, versions = sync.latest(count = 1),)
# Production workflow - sync all versionssync.workflow( name = "prod", origin = bcr, destination = prod_server, modules = core_modules, versions = sync.all(), transforms = [ sync.skip_yanked(), ],)
# Set defaultsconfig.defaults( verbose = True,)Loading Other Files
You can split configuration across multiple files:
CORE_MODULES = ["rules_go", "rules_python"]BUILD_MODULES = ["bazel_skylib", "platforms"]load("modules.star", "CORE_MODULES", "BUILD_MODULES")
sync.workflow( name = "sync-all", modules = CORE_MODULES + BUILD_MODULES, ...)Best Practices
- Use meaningful names -
bcris clearer thanr1 - Group related modules - Create lists like
core_modules,build_modules - Use environment variables - Never hardcode secrets
- Comment your config - Explain non-obvious choices
- Keep it simple - Starlark is for configuration, not business logic