YAML Anchors for Configuration Reuse
YAML anchors enable DRY (Don’t Repeat Yourself) principles in your Terrateam configuration by defining reusable templates. This reduces configuration size, ensures consistency, and makes updates easier.
When to Use YAML Anchors
Section titled “When to Use YAML Anchors”Use YAML anchors when you have:
- Multiple workflows with similar configurations
- Repeated engine settings across environments
- Common workflow step sequences
- Standardized access control patterns
- Shared directory configurations
Basic Syntax
Section titled “Basic Syntax”Define anchors in the definitions section and reference them throughout your configuration. Terrateam ignores the contents of definitions; every other key is validated against the configuration schema, so an anchored value must be valid where it is used.
definitions: std_plan: &std_plan - type: init - type: plan
workflows: - tag_query: "" plan: *std_planHow Terrateam Resolves Anchors
Section titled “How Terrateam Resolves Anchors”Terrateam resolves anchors, aliases, and the << merge key when it parses the file:
*anchorinserts the anchored value (scalar, list, or map).<<: *anchormerges the keys of an anchored map into the current map. Keys written in the current map win over merged keys.<<: [*first, *second]merges several maps. Writing<<:twice in one map is a parse error.- Merging is shallow. Nested maps are replaced, not merged.
*anchor.keyis not valid YAML. Anchor the nested value separately.- A list alias inside another list creates a nested list, which Terrateam rejects. Use the alias as the whole value or anchor the individual entries.
Common Patterns
Section titled “Common Patterns”Shared Engine Configuration
Section titled “Shared Engine Configuration”Define once, use everywhere:
definitions: standard_engine: &standard_engine name: terraform version: "1.5.7"
workflows: - tag_query: "dev" engine: *standard_engine
- tag_query: "prod" engine: <<: *standard_engine version: "1.5.5"Reusable Workflow Steps
Section titled “Reusable Workflow Steps”Anchor each step individually so they can be combined into a flat list:
definitions: # Anchor individual steps, not the surrounding list step_init: &step_init type: init step_fmt: &step_fmt type: run cmd: ["terraform", "fmt", "-check"] step_validate: &step_validate type: run cmd: ["terraform", "validate"] step_checkov: &step_checkov type: checkov step_tfsec: &step_tfsec type: run cmd: ["tfsec", "."]
workflows: - tag_query: "" plan: - *step_init - *step_fmt - *step_validate - type: plan - *step_checkov - *step_tfsecIf you want to reuse a complete step list, anchor it and reference it as the entire value (not as one entry in a larger list):
definitions: full_plan: &full_plan - type: init - type: plan - type: checkov
workflows: - tag_query: "" plan: *full_planEnvironment-Specific Configurations
Section titled “Environment-Specific Configurations”Environment variables for a step are set with the step’s env key. Define the variables once per environment and reference them from the steps that need them:
definitions: # AWS environment configurations aws_dev: &aws_dev AWS_REGION: us-east-1 AWS_ROLE_ARN: arn:aws:iam::123456789012:role/terrateam-dev ENVIRONMENT: development
aws_staging: &aws_staging AWS_REGION: us-east-1 AWS_ROLE_ARN: arn:aws:iam::123456789012:role/terrateam-staging ENVIRONMENT: staging
aws_prod: &aws_prod AWS_REGION: us-east-1 AWS_ROLE_ARN: arn:aws:iam::123456789012:role/terrateam-prod ENVIRONMENT: production
workflows: - tag_query: "dev" plan: - type: init env: *aws_dev - type: plan env: *aws_dev
- tag_query: "staging" plan: - type: init env: *aws_staging - type: plan env: *aws_staging
- tag_query: "production" plan: - type: init env: *aws_prod - type: plan env: *aws_prodApproval rules live in apply_requirements, not in workflows. Anchor them the same way:
definitions: basic_requirements: &basic_requirements approved: enabled: true any_of: ["team:developers"] any_of_count: 1 status_checks: enabled: true
strict_requirements: &strict_requirements approved: enabled: true any_of: ["team:platform"] any_of_count: 2 status_checks: enabled: true merge_conflicts: enabled: true
apply_requirements: checks: - tag_query: "dev" <<: *basic_requirements - tag_query: "staging" <<: *basic_requirements - tag_query: "production" <<: *strict_requirementsStandardized Access Control
Section titled “Standardized Access Control”Define access patterns once:
definitions: dev_team_access: &dev_team_access plan: ["*"] apply: ["team:developers", "team:platform"]
platform_only: &platform_only plan: ["*"] apply: ["team:platform"] apply_force: ["team:sre"]
access_control: enabled: true policies: - tag_query: "dev or staging" <<: *dev_team_access
- tag_query: "production" <<: *platform_only
- tag_query: "infrastructure" <<: *platform_onlyComplex Workflow Templates
Section titled “Complex Workflow Templates”Anchor individual steps so you can compose them into different workflow lists without producing nested arrays. Steps that should run even after an earlier failure use run_on: always:
definitions: # Base configuration for all workflows base_engine: &base_engine name: terraform version: "1.5.7"
# Individual step anchors (compose these into flat lists) step_init: &step_init type: init step_fmt: &step_fmt type: run cmd: ["terraform", "fmt", "-check"] step_validate: &step_validate type: run cmd: ["terraform", "validate"] step_plan: &step_plan type: plan step_checkov: &step_checkov type: checkov run_on: always step_tfsec: &step_tfsec type: run cmd: ["tfsec", ".", "--format", "json"] run_on: always step_notify: &step_notify type: run cmd: ["echo", "Deployment complete"] run_on: success
workflows: - tag_query: "feature" engine: *base_engine plan: - *step_init - *step_fmt - *step_validate - *step_plan - *step_checkov - *step_tfsec
- tag_query: "main" engine: *base_engine plan: - *step_init - *step_fmt - *step_validate - *step_plan - *step_checkov - *step_tfsec apply: - type: init - type: apply - *step_notifyDirectory Configuration Templates
Section titled “Directory Configuration Templates”Share when_modified settings and tags across directories. dirs is a map keyed by directory path (globs are allowed):
definitions: # Anchor individual tag values so they can be composed into flat lists tag_aws: &tag_aws aws tag_managed: &tag_managed managed
# Shared when_modified configuration with_shared_modules: &with_shared_modules file_patterns: ["${DIR}/*.tf", "shared/*.tf"] autoplan: true autoapply: false
# Module directories are never planned on their own module_config: &module_config file_patterns: []
dirs: terraform/networking: tags: - *tag_aws - *tag_managed - "networking" - "core" when_modified: *with_shared_modules
terraform/compute: tags: - *tag_aws - *tag_managed - "compute" - "application" when_modified: *with_shared_modules
modules/**: when_modified: *module_configAdvanced Techniques
Section titled “Advanced Techniques”Merging Multiple Anchors
Section titled “Merging Multiple Anchors”Combine several maps with one <<: key that takes a list. A key written after the merge overrides the merged value:
definitions: base: &base name: terraform
pinned: &pinned version: "1.5.5"
no_outputs: &no_outputs outputs: collect: false
workflows: - tag_query: "production" engine: <<: [*base, *pinned, *no_outputs] version: "1.5.7"Conditional Patterns
Section titled “Conditional Patterns”Anchor each step individually and assemble per-environment lists from those steps. YAML cannot merge two lists into one, so the production list has to repeat the base entries, but each step is still defined exactly once.
definitions: # Anchor individual steps step_init: &step_init type: init step_plan: &step_plan type: plan step_checkov: &step_checkov type: checkov step_compliance: &step_compliance type: run cmd: ["compliance-check"]
# Development workflow - basic dev_plan: &dev_plan - *step_init - *step_plan
# Production workflow - full compliance prod_plan: &prod_plan - *step_init - *step_plan - *step_checkov - *step_compliance
workflows: - tag_query: "dev" plan: *dev_plan
- tag_query: "production" plan: *prod_planBest Practices
Section titled “Best Practices”- Name anchors descriptively - Use clear names that indicate purpose
- Group related anchors - Keep similar configurations together
- Document complex anchors - Add comments explaining usage
- Start simple - Begin with basic patterns and evolve as needed
- Test thoroughly - Run
terrateam repo-configon a pull request to verify the resolved configuration before relying on it
Example: Complete Multi-Environment Setup
Section titled “Example: Complete Multi-Environment Setup”definitions: # Terraform version tf_engine: &tf_engine name: terraform version: "1.5.7"
# Individual step anchors (compose into flat lists below) step_init: &step_init type: init step_fmt: &step_fmt type: run cmd: ["terraform", "fmt", "-check"] step_validate: &step_validate type: run cmd: ["terraform", "validate"] step_plan: &step_plan type: plan step_checkov: &step_checkov type: checkov
# Environment credentials dev_env: &dev_env AWS_ROLE_ARN: arn:aws:iam::111111111111:role/terrateam-dev AWS_REGION: us-east-1
prod_env: &prod_env AWS_ROLE_ARN: arn:aws:iam::222222222222:role/terrateam-prod AWS_REGION: us-east-1
# Access patterns dev_access: &dev_access plan: ["*"] apply: ["team:developers"]
prod_access: &prod_access plan: ["*"] apply: ["team:platform"] apply_force: ["team:sre"]
# Approval rules dev_checks: &dev_checks approved: enabled: true any_of: ["team:developers"] any_of_count: 1
prod_checks: &prod_checks approved: enabled: true any_of: ["team:platform"] any_of_count: 2 status_checks: enabled: true
workflows: - tag_query: "dev" engine: *tf_engine plan: - *step_init - *step_fmt - *step_validate - type: plan env: *dev_env - *step_checkov apply: - *step_init - type: apply env: *dev_env
- tag_query: "production" engine: *tf_engine plan: - *step_init - *step_fmt - *step_validate - type: plan env: *prod_env - *step_checkov apply: - *step_init - type: apply env: *prod_env
apply_requirements: checks: - tag_query: "dev" <<: *dev_checks - tag_query: "production" <<: *prod_checks
access_control: enabled: true policies: - tag_query: "dev" <<: *dev_access - tag_query: "production" <<: *prod_accessThis approach keeps every setting defined once while producing a configuration Terrateam accepts as written.