Skip to main content

!labels

The !labels YAML function reads the current component’s resolved metadata.labels. Use it without arguments to return a map of strings, or supply a key to retrieve one string value with an optional fallback.

Usage​

Use bare !labels to return the full map:

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

Arguments​

key (optional)
The literal, case-sensitive label key. Without it, the result is the complete label map. Keys containing dots, slashes, or hyphens are read literally; they are not nested paths.
default (optional)
A string returned when the key is absent. Quote values containing spaces, or use "" for an explicit empty fallback. Without a fallback, a missing key produces an error. An existing empty label value is returned unchanged.

The function accepts at most two arguments. Empty keys and malformed arguments are errors.

How It Works​

Atmos reads the labels after stack defaults and component inheritance have been merged. These are the same labels used by atmos list components --labels. If labels are unset, bare !labels returns an empty map. A key lookup instead uses its explicit fallback or reports the missing key.

Single label lookup​

stack.yaml
components:
terraform:
vpc:
metadata:
labels:
compliance: sox
cost-center: platform
runner: self-hosted-large
vars:
compliance: !labels compliance
cost_center: !labels cost-center
owner: !labels owner "Platform Team"
optional: !labels missing ""
settings:
pro:
pull_request:
synchronize:
workflows:
atmos-terraform-plan.yaml:
inputs:
component: "{{ .atmos_component }}"
stack: "{{ .atmos_stack }}"
runner: !labels runner ubuntu-latest

Here compliance resolves to sox, cost_center to platform, owner to Platform Team, and optional to an empty string. The runner resolves to self-hosted-large. See runner routing for the workflow input and job configuration.

Go template equivalents​

Individual labels are also available through the template context:

vars:
compliance: '{{ .metadata.labels.compliance }}'
cost_center: '{{ index .metadata.labels "cost-center" }}'

The path is .metadata.labels, not a top-level .labels shortcut. These examples require the labels to exist. For an explicit missing-key fallback, use !labels key default.

Bridging metadata.labels into vars.tags​

The most common use of !labels is to bridge Atmos's own metadata.labels (used for CLI categorization and filtering) into the map-shaped vars.tags/vars.labels that terraform-null-label-style modules expect for actual cloud resource tagging:

stack.yaml
components:
terraform:
vpc:
metadata:
tags: [production, networking]
labels:
Namespace: eg
Environment: prod
cost-center: platform
vars:
# var.tags (map, AWS/terraform-null-label convention) <- metadata.labels
tags: !labels
Why vars.tags: !labels isn't a typo

Terraform/AWS-style modules call their map-shaped resource-tagging input tags (var.tags map(string)) — the same "AWS calls a map a tag" naming that Atmos's tags-vs-labels standard distinguishes: a list is a tag, a map is a label. So !labels — which returns the map — is what belongs in a module's tags variable. !tags returns Atmos's own []string list and is for a different shape of consumer entirely.

Examples​

Bridging into a Terraform module​

stack.yaml
components:
terraform:
vpc:
metadata:
labels:
cost-center: platform
compliance: sox
vars:
tags: !labels

No Labels Set​

stack.yaml
components:
terraform:
rds:
vars:
# labels will be {} (empty map, not an error)
labels: !labels
  • !tags - Get the current component's own metadata.tags as a list
  • !labels.keys - Get the current component's metadata.labels keys
  • !labels.values - Get the current component's metadata.labels values