Configure Variables
The vars section defines variables that are passed to your components. Variables can be set at the global level, component-type level, or component level, and are deep-merged across the inheritance chain.
Use Cases
- Component Configuration: Pass input variables to Terraform root modules, Helmfile releases, Packer templates, or Ansible playbooks.
- Environment-Specific Values: Define different values for dev, staging, and production environments.
- Shared Defaults: Set common variables at higher levels and override them at lower levels as needed.
Configuration Scopes
The vars section can be defined at multiple levels. Atmos deep-merges variables from all levels, with more specific levels taking precedence.
Global Level
Variables defined at the root level apply to all components in the stack:
# stacks/orgs/acme/plat/prod/us-east-1.yaml
vars:
environment: prod
region: us-east-1
tags:
Environment: Production
ManagedBy: Atmos
Component-Type Level
Variables defined under terraform, helmfile, packer, or ansible apply to all components of that type:
# stacks/orgs/acme/plat/prod/_defaults.yaml
terraform:
vars:
terraform_version: "1.5"
helmfile:
vars:
helm_timeout: 300
ansible:
vars:
managed_by: Atmos
Component Level
Variables defined within a component override all higher-level settings:
# stacks/orgs/acme/plat/prod/us-east-1.yaml
components:
terraform:
vpc:
vars:
vpc_cidr: "10.0.0.0/16"
enable_dns_hostnames: true
availability_zones:
- us-east-1a
- us-east-1b
- us-east-1c
Merge Behavior
Variables are deep-merged from the most general to the most specific level:
- Global
vars:(applies to all components) - Component-type
terraform.vars:/helmfile.vars:/packer.vars:/ansible.vars:(applies to all components of that type) - Base component
vars(inherited viametadata.inherits) - Component
components.terraform.<name>.vars(applies to a specific component) - Override
overrides.vars(file-scoped — applies only to components in the current manifest and its imports)
Maps are recursively merged, and lists are replaced (not appended). More specific values override less specific ones.
Import order determines who wins at the same scope level. Scope level determines who wins across levels. Use atmos describe component <component> -s <stack> --provenance to see exactly where each value came from.
Example
stacks/catalog/vpc/_defaults.yaml
stacks/orgs/acme/plat/prod/_defaults.yaml
stacks/orgs/acme/plat/prod/us-east-1.yaml
The resulting vars for the vpc component would be:
vars:
vpc_cidr: "10.0.0.0/16"
tags:
Team: Platform # From catalog/_defaults
Environment: Production # From prod/_defaults
Name: prod-vpc # From component
Context Variables
Atmos automatically provides context variables based on your stack naming convention. These are available in templates and can be used in your Terraform code:
namespace- Organization or company identifier.
tenant- Tenant identifier (for multi-tenant setups).
environment- Environment identifier (e.g.,
ue1for us-east-1). stage- Stage identifier (e.g.,
dev,staging,prod).
These context variables are typically configured in your atmos.yaml using the name_pattern setting.
Using Templates in Variables
Variables support Go templates for dynamic values:
vars:
cluster_name: "{{ .namespace }}-{{ .environment }}-{{ .stage }}-eks"
bucket_name: "{{ .namespace }}-{{ .tenant }}-{{ .stage }}-assets"
You can also reference other component outputs using YAML functions:
vars:
vpc_id: !terraform.output vpc/vpc_id
subnet_ids: !terraform.output vpc/private_subnet_ids
YAML Functions for Variables
Atmos provides YAML functions that can dynamically set variable values. These functions are evaluated at runtime when processing stack configurations.
!include - Load External Files
The !include function loads content from external files, making it ideal for reusing existing .tfvars files or large variable definitions:
vars:
# Include an entire tfvars file
!include path/to/variables.tfvars
# Or include specific variable files
network_config: !include config/network.yaml
tags: !include config/common-tags.yaml
This is particularly useful when:
- Migrating from native Terraform with existing
.tfvarsfiles - Sharing variable definitions across multiple components
- Keeping large configuration blocks in separate files
!terraform.output - Reference Component Outputs
Read outputs from other Terraform components:
vars:
vpc_id: !terraform.output vpc/vpc_id
subnet_ids: !terraform.output vpc/private_subnet_ids
!terraform.state - Access Remote State
Access values from Terraform state with more control:
vars:
# From same stack
vpc_id: !terraform.state vpc vpc_id
# From different stack
shared_vpc_id: !terraform.state shared-services/network vpc vpc_id
!store - Read from External Stores
Read values from external key-value stores:
vars:
api_key: !store ssm/prod app api_key
db_password: !store vault/secrets database password
!env - Read Environment Variables
Pass through environment variables:
vars:
aws_region: !env AWS_REGION
deploy_env: !env DEPLOY_ENV, development # With default
!exec - Execute Commands
Execute shell commands and use their output:
vars:
git_commit: !exec git rev-parse HEAD
current_user: !exec whoami
For the complete list of YAML functions, see YAML Functions.
Best Practices
-
Use Catalog Defaults: Define common variable patterns in
stacks/catalog/and import them. -
Keep Variables DRY: Set shared values at higher levels and only override what's different at lower levels.
-
Use Meaningful Names: Variable names should match your Terraform variable names for clarity.
-
Document Required Variables: Use abstract components to enforce required variables through inheritance.
-
Avoid Duplication: If you find yourself repeating the same variables, consider using imports or inheritance.