anvil.yaml Reference
Use this page when you need the exact anvil.yaml field names and merge rules.
Anvil looks for anvil.yaml and then anvil.yml directly inside the project
directory passed to the CLI. It does not walk parent directories. A project can
run without a config file unless a profile is selected; profiles require a config
file because there is nothing to overlay without one.
Complete Shape
Section titled “Complete Shape”project: name: string version: string
main: string
scan: dirs: [string] patterns: [string] exclude: [string]
generator: output: string output_dir: string package: string patterns: [string] stages: [string]
generate: output: string output_dir: string package: string patterns: [string] stages: [string]
build: main: string output: string tags: [string]
compiler: rules: [string]
testbed: scripts: [string]
dev: main: string main_path: string work_dir: string watch_dirs: [string] watch_exts: [string] run: string argv: [string] env: NAME: value
stages: name: description: string commands: [string] rules: [string]
commands: name: run: string argv: [string] dir: string env: NAME: value
profiles: name: # same fields as the root config except profilesProject
Section titled “Project”project.name is the human-readable project name. anvil build uses it as
the default binary name when build.output is empty.
project.version is project-owned version metadata. The CLI parses and
preserves it through profile overlays. It does not affect generated code,
OpenAPI output, or build output.
main points at the application entrypoint package. Config.MainPackage()
selects the first non-empty value from:
build.main- top-level
main dev.main_pathdev.main.
scan.patterns wins when present and is passed as Go package patterns.
scan.dirs is converted to recursive package patterns:
.becomes./..../apibecomes./api/...apibecomes./api/...
scan.exclude is parsed and carried by config. The scanner does not filter
packages with it.
scan.dirs and scan.patterns are interpreted from the project directory by
Go package loading. They are not rewritten by Anvil’s path resolver.
Generator And Generate
Section titled “Generator And Generate”generator is preferred. generate is a compatibility alias. When both are
set, generator values win unless a specific generator field is empty.
Fields:
output: generated Go file pathoutput_dir: generated output directorypackage: package name for generated codepatterns: generation-specific scan patternsstages: parsed by config, not used for rule selection
Output path precedence is:
- CLI output argument
generator.outputgenerate.outputgenerator.output_dirgenerate.output_dir<project-dir>/anvilgen/anvil_autogenerated.go
When the selected output ends with .go, it is treated as the generated file.
Otherwise it is treated as a directory and Anvil writes
anvil_autogenerated.go inside it.
If package is empty, the package name is derived from the output directory.
Invalid identifier characters become _, and names starting with a digit are
prefixed with anvilgen_.
build.main overrides top-level main for build workflows.
build.output is the desired binary path.
build.tags are Go build tags for anvil build. The command also accepts
extra --tags values and appends them.
Compiler
Section titled “Compiler”compiler.rules is an ordered list of Starlark rule files. Paths are resolved
relative to the config file directory.
Rules run during generate and lint. Those commands also run Anvil’s
built-in manifest rules. manifest, openapi, and testbed build from the
manifest without running configured rules.
Testbed
Section titled “Testbed”testbed.scripts lists YAML scripts used to alter or extend generated testbed
suites.
dev describes local run behavior:
main,main_path: dev-specific entrypoint fieldswork_dir: working directory for dev commandswatch_dirs: directories to watchwatch_exts: file extensions to watchrun: executableargv: argumentsenv: environment overlay
Define either dev.run or dev.argv, not both. argv runs directly without a
shell. run uses the system shell.
watch_exts defaults to .go, .yaml, .yml, and .env. Entries without a
leading dot are normalized. The watcher skips .git, vendor, node_modules,
bin, dist, and the generated output directory.
Path Resolution
Section titled “Path Resolution”These paths are resolved against the directory containing anvil.yaml:
- Top-level
main. generator.output,generator.output_dir,generate.output, andgenerate.output_dir.build.mainandbuild.output.compiler.rules.testbed.scripts.dev.main,dev.main_path,dev.work_dir, anddev.watch_dirs.- Stage rule files.
- Command directories.
scan.dirs and scan.patterns are not in this list because they are Go
package patterns.
Package pattern precedence is:
- CLI package-pattern arguments.
scan.patterns.scan.dirsconverted to recursive package patterns.generator.patternsorgenerate.patterns.- The command default.
Stages
Section titled “Stages”Stages group commands and rules:
stages: ci: description: CI checks commands: [test, lint] rules: - ./tools/anvil/rules/ci.starStage rules are appended after compiler.rules. Stage names are sorted before
their rules are appended, so the final order is deterministic.
Commands
Section titled “Commands”Commands are named executable definitions:
commands: test: argv: ["go", "test", "./..."] dir: . env: APP_ENV: testDefine either run or argv, not both. argv runs without a shell. run
uses the system shell (cmd /C on Windows, sh -c elsewhere).
Profiles
Section titled “Profiles”Profiles are sparse overlays. Profile fields replace or merge root fields according to the config type:
- Strings replace only when non-empty
- Slices replace only when non-empty
- Maps merge by key
envmaps merge by key- Profile
generateandgeneratorare both accepted. When both appear in one profile,generateoverlaysgeneratorfor theConfig.Generation()view. Keep them identical unless that overlay is intentional. runandargvare replaced together when a profile defines either one
Unknown profiles fail with unknown anvil profile "<name>".
Profiles can be selected with --profile <name>, -p <name>, or
ANVIL_PROFILE. A CLI profile flag wins over the environment variable.
Stage rules are always appended after compiler.rules in sorted stage-name
order. generator.stages is parsed but not used to select a subset of stages;
use profiles when environments need different rule files.