build.yaml Reference#
Source of truth:
build/build_config/lib/src/— package version 1.3.0
The build.yaml file lives at the root of your package and tells build_runner
about your builders, their configuration, and how they apply to packages.
Top-Level Sections#
builders: # Declare Builder implementations
post_process_builders: # Declare PostProcessBuilder implementations
targets: # Configure which sources each builder runs on
global_options: # Override builder options globally (in consuming packages)
additional_public_assets: [] # Extra assets to expose publicly from this package
builders: Section#
Each key under builders: is a builder name. The full builder key is package_name|builder_name.
builders:
my_builder:
# Required: Dart import for the builder factory
import: "package:my_package/builder.dart"
# Required: List of top-level function names matching BuilderFactory typedef
builder_factories: ["myBuilder"]
# Required: Map from input extension(s) to output extension(s)
# See patterns below
build_extensions: {".dart": [".g.dart"]}
# When to apply this builder automatically.
# Options: none | dependents | allPackages | rootPackage
# Default: none
auto_apply: dependents
# Where generated files go.
# cache: in build cache (invisible to user, default for source_gen part builders)
# source: written to disk alongside source files (like dart_mappable's .mapper.dart)
# Default: cache
build_to: cache
# Whether this builder is "lazy" — only runs if its output is needed
# Default: false
is_optional: false
# Extensions that MUST exist before this builder runs (for ordering)
# The builder still runs even if required_inputs aren't present —
# it's purely for ordering, not filtering
required_inputs: [".freezed.dart"]
# Builder keys that should run AFTER this builder
# Format: "package_name|builder_name"
runs_before: ["other_package|other_builder"]
# Builders that should be applied when this builder is applied
# Most common: tells build_runner to also run source_gen's combining_builder
# which merges .g.part files into a single .g.dart
applies_builders: ["source_gen|combining_builder"]
# Default configuration for consuming packages
defaults:
generate_for:
- "lib/**"
- "!lib/**/*.g.dart"
options:
some_option: value
dev_options:
verbose: true
release_options:
verbose: false
build_extensions Patterns#
# Simple suffix — matches any file with that extension
build_extensions: {".dart": [".g.dart"]}
# Multiple outputs from one input
build_extensions: {".dart": [".mapper.dart", ".init.dart"]}
# Multiple input extensions
build_extensions:
".dart": [".g.dart"]
".json": [".dart"]
# Path-anchored (^ prefix) — only this exact path
build_extensions: {"^pubspec.yaml": ["lib/src/pubspec.g.dart"]}
# Capture group ({{}}) — captures part of the path
build_extensions: {"^assets/{{}}.json": ["lib/generated/{{}}.dart"]}
# assets/users.json → lib/generated/users.dart
# Package-level ($package$) — runs exactly once per package
build_extensions: {r"$package$": ["lib/generated/all_mappers.dart"]}
auto_apply Values#
| Value | Behavior |
|---|---|
none |
Never auto-applied; must be explicitly enabled in targets: |
dependents | Applied to packages that directly depend on this package |
allPackages | Applied to all packages in the build |
rootPackage | Applied only to the root (currently being built) package |
Most annotation-driven generators use dependents — they run on packages that depend
on your annotations package.
build_to Values#
| Value | Behavior |
|---|---|
cache |
Files go to the build cache, not visible on disk. Used by source_gen part builders. |
source |
Files written to disk next to source files. Used by dart_mappable (.mapper.dart). |
Important: When build_to: source, the generated files appear in the source tree and should be committed. When
build_to: cache, they're regenerated on each build.
post_process_builders: Section#
Post-process builders run after all regular builders and have limited access (only their primary input).
post_process_builders:
my_post_builder:
import: "package:my_package/builder.dart"
# Only ONE factory function (not a list, unlike builders:)
builder_factory: "myPostBuilder"
# Extensions of files to process
input_extensions: [".dart"]
# cache or source
build_to: cache
defaults:
generate_for: ["lib/**"]
options: {}
targets: Section#
Used within packages to configure how builders apply to their own source files.
targets:
# $default is the standard target for a package's lib/ sources
$default:
# Glob patterns for files included in this target
# Exclusions start with !
sources:
- "lib/**"
- "test/**"
- "!lib/**/*.g.dart"
# Whether build_runner should auto-apply builders from dependencies
# Default: true
auto_apply_builders: true
# Per-builder configuration overrides
builders:
# Key format: "package_name|builder_name"
"source_gen|combining_builder":
options:
ignore_for_file:
- "lines_longer_than_80_chars"
"json_serializable|json_serializable":
# Enable or disable this builder for this target
enabled: true
# Glob patterns (relative to package root) for which inputs this builder runs on
generate_for:
- "lib/src/**"
- "test/**"
# Exclusions:
- "!lib/src/generated/**"
# Options passed to the builder (builder reads from BuilderOptions.config)
options:
field_rename: snake
explicit_to_json: true
# Options only in dev builds (dart pub get vs dart pub get --no-precompile)
dev_options:
checked: true
# Options only in release builds
release_options:
checked: false
# You can define multiple targets (unusual but possible)
my_tests:
sources: ["test/**"]
builders:
"my_package|my_builder":
enabled: true
global_options: Section#
Used in consuming packages to override builder options globally. This is what end-users put in their
build.yaml to configure your generator:
global_options:
"json_serializable|json_serializable":
options:
field_rename: snake
explicit_to_json: true
runs_before: []
Complete Real-World Examples#
json_serializable's build.yaml (generator package)#
builders:
json_serializable:
import: "package:json_serializable/builder.dart"
builder_factories: ["jsonSerializable"]
build_extensions: {".dart": ["json_serializable.g.part"]}
auto_apply: dependents
build_to: cache
applies_builders: ["source_gen|combining_builder"]
Key points:
- Output is
.g.part(not.g.dart) — source_gen's combining_builder merges it applies_builders: ["source_gen|combining_builder"]is required for the merge step-
build_to: cache— the.g.partis invisible, the.g.dartis in cache too
retrofit's build.yaml (generator package)#
builders:
retrofit_generator:
import: "package:retrofit_generator/retrofit_generator.dart"
builder_factories: ["retrofitBuilder"]
build_extensions: { ".dart": [".retrofit.g.part"] }
auto_apply: dependents
build_to: cache
applies_builders: ["source_gen|combining_builder"]
dart_mappable_builder's build.yaml (source output)#
builders:
dart_mappable_builder:
import: "package:dart_mappable_builder/dart_mappable_builder.dart"
builder_factories: [ "buildMappable" ]
build_extensions: { ".dart": [ ".mapper.dart", ".init.dart" ] }
required_inputs: [".freezed.dart"]
auto_apply: dependents
build_to: source
Key points:
-
build_to: source— outputs are.mapper.dartand.init.dartfiles on disk required_inputs: [".freezed.dart"]— ensures freezed runs first (ordering only)- No
applies_buildersneeded — outputs directly to disk, no combining step
Consuming package build.yaml (example)#
# In the app that uses your generator
targets:
$default:
builders:
"my_generator|my_builder":
options:
output_prefix: "_generated"
generate_for:
- "lib/models/**"
How build_runner Discovers and Orders Builders#
- Reads
build.yamlfrom every package in the dependency graph - Creates
BuilderDefinitionobjects from eachbuilders:entry -
Orders builders using a topological sort based on:
runs_beforedeclarationsrequired_inputs(implies ordering)applies_builders(implied dependency)
-
For each source file matching
build_extensionsinput, callsBuilder.build() - Post-process builders run in a final phase after all regular builders
Common Mistakes#
| Mistake | Fix |
|---|---|
| Forgot `applies_builders: ["source_gen | combining_builder"]` |
Used builder_factory (singular) under builders: |
Use builder_factories (plural, a list) for regular builders |
Used builder_factories under post_process_builders: |
Use builder_factory (singular) for post-process builders |
required_inputs is not filtering |
It only controls ordering, not whether the builder runs |
auto_apply: dependents but builder not running |
Check that the generator package is a dev_dependency in the consuming package |
build_to: cache but file not found on disk |
Expected — cache files aren't on disk; use build_to: source if you need them visible |