Skip to main content

Configure Component Metadata

The metadata section configures how Atmos interprets and manages a component. Most metadata fields are only valid within component definitions (components.terraform.<name>.metadata). A restricted subset of fields (labels, tags, custom, enabled, locked, terraform_workspace_pattern) can also be set stack-wide as a default.

Use Cases

  • Component Mapping: Specify which Terraform root module a component uses.
  • Human-Readable Descriptions: Document what a component is for.
  • Inheritance: Define which components a component inherits from.
  • Abstract Components: Mark components as templates that cannot be deployed directly.
  • Component Control: Enable, disable, or lock components.

Configuration Scope

Most metadata fields are only valid inside component definitions:

components:
terraform:
vpc:
metadata:
component: vpc/network
inherits:
- vpc/defaults

Component-identity fields — component, inherits, type, name, terraform_workspace — cannot be set at the global level or under terraform: / helmfile: / packer: defaults. Setting one of these fields at global scope is a hard error, since applying the same component path or inheritance chain to every component in a stack would be a misconfiguration, not a useful default.

Global (stack-wide) metadata

A restricted allowlist of metadata fields — the ones that are data bags or simple gates rather than component identity — can be set at the root of a stack manifest (for example in _defaults.yaml), and are deep-merged as a default into every component's own metadata:

_defaults.yaml
metadata:
labels:
org: acme
enabled: true

Allowed at global scope: labels, tags, custom, enabled, locked, terraform_workspace_pattern. Any other field (component, inherits, type, name, terraform_workspace) is rejected with an error if set here.

Precedence, lowest to highest:

  1. Global metadata: (stack-wide default)
  2. The metadata.inherits base-component chain
  3. The component's own local metadata: block — always wins
_defaults.yaml
metadata:
labels:
org: acme
stacks/catalog/vpc.yaml
components:
terraform:
vpc:
metadata:
labels:
org: platform-team # overrides the global "org: acme" for this component
vars:
tags: !labels

Here vars.tags resolves to {org: platform-team} for the vpc component, while any component that doesn't set its own metadata.labels.org gets {org: acme} from the global default.

Metadata Fields

component

Specifies the path to the Terraform root module, relative to your components directory:

components:
terraform:
vpc-prod:
metadata:
component: vpc # Uses components/terraform/vpc
description: Production VPC
vars:
environment: prod

This allows multiple stack components to share the same Terraform root module with different configurations.

description

Provides a human-readable description of the component:

components:
terraform:
vpc:
metadata:
component: vpc
description: "Virtual Private Cloud with public and private subnets"

Atmos preserves description as component metadata. It does not change how the component is processed, planned, or applied.

name

Provides a stable logical identity for the component, used to generate the backend workspace_key_prefix. This is especially important when using versioned component folders:

components:
terraform:
vpc:
metadata:
name: vpc # Stable logical identity
component: vpc/v2 # Physical version path

Why this matters: Without name, the workspace_key_prefix is auto-generated from component, which includes the version (vpc-v2). When you upgrade to vpc/v3, the workspace key prefix changes, creating a new state file and losing your existing infrastructure state.

With metadata.name: The workspace key prefix stays stable (vpc) across version upgrades, so your Terraform state path remains vpc/{workspace}/terraform.tfstate regardless of which version you're running.

See Workspace Key Management for more details.

inherits

Defines a list of components from which this component inherits configuration:

components:
terraform:
vpc/defaults:
metadata:
type: abstract
vars:
enable_dns_hostnames: true
enable_dns_support: true

vpc-prod:
metadata:
inherits:
- vpc/defaults
vars:
vpc_cidr: "10.0.0.0/16"

Inheritance is processed in order, with later items and the component's own values taking precedence. For detailed inheritance behavior, see Inheritance.

type

Marks a component as abstract or real (default):

components:
terraform:
vpc/base:
metadata:
type: abstract # Cannot be deployed directly
vars:
enable_dns_hostnames: true

Abstract components:

  • Serve as templates for other components to inherit from
  • Cannot be deployed with atmos terraform apply
  • Do not appear in atmos describe stacks output by default
  • Are useful for DRY configuration patterns

enabled

Controls whether a component is active:

components:
terraform:
monitoring:
metadata:
enabled: false # Component is disabled
vars:
# ...

When enabled: false:

  • The component is skipped during atmos terraform apply
  • The component does not appear in active stack listings
  • Useful for conditionally disabling components per environment

enabled can also be set as a global default to disable every component in a stack unless a component overrides it.

locked

Prevents modifications to a component:

components:
terraform:
core-network:
metadata:
locked: true # Prevent changes
vars:
# ...

When locked: true:

  • Atmos will warn or prevent changes to the component
  • Useful for protecting critical infrastructure components

locked can also be set as a global default to lock every component in a stack unless a component overrides it.

terraform_workspace

Overrides the Terraform workspace name with a literal string value:

components:
terraform:
vpc:
metadata:
terraform_workspace: "custom-workspace-name"

By default, Atmos calculates workspace names automatically based on the stack name. Use this field when you need explicit control over the workspace name.

For detailed information about how Atmos manages Terraform workspaces, see Workspaces.

terraform_workspace_pattern

Overrides the Terraform workspace name using a pattern with context tokens:

components:
terraform:
vpc:
metadata:
terraform_workspace_pattern: "{tenant}-{environment}-{stage}"

terraform_workspace_pattern can also be set as a global default, unlike terraform_workspace (an explicit value, which would collide across components if applied stack-wide and so is component-only).

Supported tokens:

  • {namespace} - The namespace from context variables
  • {tenant} - The tenant from context variables
  • {environment} - The environment from context variables
  • {region} - The region from context variables
  • {stage} - The stage from context variables
  • {attributes} - The attributes from context variables
  • {component} - The Atmos component name
  • {base-component} - The base component name (from metadata.component)

For detailed information about workspace patterns and examples, see Workspaces.

custom

A user extension point for storing arbitrary metadata that Atmos preserves but does not interpret:

components:
terraform:
vpc:
metadata:
custom:
owner: platform-team
cost_center: "12345"
tier: critical

Use custom for:

  • Storing metadata for external tooling to consume (CI/CD pipelines, dashboards)
  • Adding labels or annotations readable via atmos describe stacks
  • Custom categorization that doesn't affect Atmos behavior
note

The custom section is inherited from base components when stacks.inherit.metadata is enabled (the default). Like other metadata fields, values from derived components override inherited values, and nested maps are deep-merged. custom can also be set as a global default.

tags

A list of tags used to select this component with the --tags flag on commands like atmos list components, atmos terraform plan/apply/deploy, and the native Kubernetes/Helm/container commands:

components:
terraform:
vpc:
metadata:
tags:
- production
- tier-1

--tags matches any of the given tags (OR semantics). For example, atmos terraform apply --tags production,tier-1 applies components tagged production or tier-1.

tags can also be set as a global default.

labels

A map of key: value labels used to select this component with the --labels flag, similar to a Kubernetes label selector:

components:
terraform:
vpc:
metadata:
labels:
cost-center: platform
compliance: sox

--labels matches all of the given key=value pairs (AND semantics). For example, atmos terraform apply --labels cost-center=platform,compliance=sox only applies components whose metadata.labels contain both cost-center: platform and compliance: sox.

labels can also be set as a global default.

Selector Purity

Labels and tags are selectors: Atmos evaluates them before authentication, template processing, and YAML function execution to decide which components a command operates on. By design, their values must be resolvable without authenticating or executing external processes — this keeps selection fast, deterministic, and credential-free.

Allowed in metadata.tags and metadata.labels:

  • Plain strings
  • Simple Go templates over the stack context (for example, {{ .vars.stage }})
  • Local YAML functions: !env, !git.*, !include

Rejected with a hard error on any command that enumerates stacks (describe stacks, describe affected, the list commands, and multi-component terraform selections such as --all and --affected):

  • YAML functions that require authentication or process execution: !terraform.state, !terraform.output, !store, !store.get, !secret, !aws.*, !emulator, !exec, !random
  • Template calls to atmos.Component, atmos.Store, atmos.GomplateDatasource, atmos.Resolve, gomplate datasources (ds/datasource, include, datasourceExists, datasourceReachable, defineDatasource), the gomplate aws.*/gcp.*/net.*/random.* namespaces, and network or non-deterministic template functions (getHostByName, uuidv4, randAlpha, randAlphaNum, randNumeric, randAscii, randBytes, now)

The error names the offending component and stack manifest. If a value needs one of these constructs, move it into vars or settings and reference it from there — the value stays available to the component while the selectors remain pure.

If upgrading surfaces this error for existing manifests and you need time to migrate, set describe.settings.eager_evaluation: true in atmos.yaml: it disables pre-evaluation scoping entirely (every stack is fully evaluated before filtering, matching pre-optimization behavior), under which selectors are evaluated like any other value and the purity contract is not enforced.

Examples

Multiple Instances from One Module

Deploy the same VPC module in different configurations:

stacks/orgs/acme/plat/prod/us-east-1.yaml
components:
terraform:
vpc-main:
metadata:
component: vpc
description: Main VPC
vars:
vpc_cidr: "10.0.0.0/16"
name: main

vpc-isolated:
metadata:
component: vpc
description: Isolated VPC without an internet gateway
vars:
vpc_cidr: "10.1.0.0/16"
name: isolated
enable_internet_gateway: false

Both vpc-main and vpc-isolated use the same components/terraform/vpc root module but with different configurations.

Abstract Base with Concrete Implementations

stacks/catalog/vpc/_defaults.yaml
components:
terraform:
vpc/defaults:
metadata:
type: abstract
component: vpc
vars:
enable_dns_hostnames: true
enable_dns_support: true
enable_nat_gateway: true
single_nat_gateway: false
stacks/orgs/acme/plat/prod/us-east-1.yaml
import:
- catalog/vpc/_defaults

components:
terraform:
vpc:
metadata:
inherits:
- vpc/defaults
vars:
vpc_cidr: "10.0.0.0/16"
availability_zones:
- us-east-1a
- us-east-1b
- us-east-1c

Environment-Specific Component Control

stacks/orgs/acme/plat/dev/us-east-1.yaml
components:
terraform:
expensive-feature:
metadata:
enabled: false # Disabled in dev to save costs
vars:
# ...
stacks/orgs/acme/plat/prod/us-east-1.yaml
components:
terraform:
expensive-feature:
metadata:
enabled: true # Enabled in production
vars:
# ...

Multi-Level Inheritance

stacks/catalog/components.yaml
components:
terraform:
# Level 1: Base defaults
base/defaults:
metadata:
type: abstract
vars:
tags:
ManagedBy: Atmos

# Level 2: VPC defaults inheriting from base
vpc/defaults:
metadata:
type: abstract
component: vpc
inherits:
- base/defaults
vars:
enable_dns_hostnames: true

# Level 3: Production VPC inheriting from vpc/defaults
vpc/prod:
metadata:
type: abstract
inherits:
- vpc/defaults
vars:
enable_nat_gateway: true
multi_az: true

Best Practices

  1. Use Abstract Components: Create abstract base components for shared configuration to keep your stacks DRY.

  2. Meaningful Component Names: Use descriptive names that indicate the component's purpose and any specialization (e.g., vpc/prod, vpc/isolated).

  3. Document Inheritance: Keep inheritance chains shallow (2-3 levels) and well-documented for maintainability.

  4. Protect Critical Components: Use locked: true for infrastructure components that should not change without careful review.

  5. Use enabled for Environment Differences: Rather than duplicating component definitions, use enabled to control which components are active per environment.