Skip to content

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.

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 profiles

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:

  1. build.main
  2. top-level main
  3. dev.main_path
  4. dev.main
  5. .

scan.patterns wins when present and is passed as Go package patterns.

scan.dirs is converted to recursive package patterns:

  • . becomes ./...
  • ./api becomes ./api/...
  • api becomes ./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 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 path
  • output_dir: generated output directory
  • package: package name for generated code
  • patterns: generation-specific scan patterns
  • stages: parsed by config, not used for rule selection

Output path precedence is:

  1. CLI output argument
  2. generator.output
  3. generate.output
  4. generator.output_dir
  5. generate.output_dir
  6. <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.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.scripts lists YAML scripts used to alter or extend generated testbed suites.

dev describes local run behavior:

  • main, main_path: dev-specific entrypoint fields
  • work_dir: working directory for dev commands
  • watch_dirs: directories to watch
  • watch_exts: file extensions to watch
  • run: executable
  • argv: arguments
  • env: 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.

These paths are resolved against the directory containing anvil.yaml:

  • Top-level main.
  • generator.output, generator.output_dir, generate.output, and generate.output_dir.
  • build.main and build.output.
  • compiler.rules.
  • testbed.scripts.
  • dev.main, dev.main_path, dev.work_dir, and dev.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:

  1. CLI package-pattern arguments.
  2. scan.patterns.
  3. scan.dirs converted to recursive package patterns.
  4. generator.patterns or generate.patterns.
  5. The command default.

Stages group commands and rules:

stages:
ci:
description: CI checks
commands: [test, lint]
rules:
- ./tools/anvil/rules/ci.star

Stage rules are appended after compiler.rules. Stage names are sorted before their rules are appended, so the final order is deterministic.

Commands are named executable definitions:

commands:
test:
argv: ["go", "test", "./..."]
dir: .
env:
APP_ENV: test

Define either run or argv, not both. argv runs without a shell. run uses the system shell (cmd /C on Windows, sh -c elsewhere).

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
  • env maps merge by key
  • Profile generate and generator are both accepted. When both appear in one profile, generate overlays generator for the Config.Generation() view. Keep them identical unless that overlay is intentional.
  • run and argv are 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.