YAML in Atmos
Atmos uses YAML as its configuration language because it's human-readable, portable, and powerful enough to handle complex infrastructure configurations. YAML in Atmos has a few party tricks up its sleeve—especially around scope, merging, and some practical considerations like type inference and quoting conventions.
Let's clear up the most common misconceptions and show you how to use YAML effectively in Atmos.
Why YAML for Configuration?
YAML is ideal for infrastructure configuration because:
✅ Human-readable - Easy to read, write, and review in PRs
✅ Supports comments - Document your configuration inline
✅ Hierarchical - Natural fit for nested infrastructure config
✅ Portable - Every language can parse it
✅ Type-aware - Strings, numbers, booleans, null
✅ Schema validation - Validate with JSON Schema or OPA policies
Compare to alternatives:
| Format | Comments | Hierarchy | Schema Validation | Complexity |
|---|---|---|---|---|
| YAML | ✅ | ✅ | ✅ | Low |
| JSON | ❌ | ✅ | ✅ | Low |
| HCL | ✅ | ✅ | ❌ | Medium |
YAML keeps configuration simple while HCL handles the infrastructure logic.
YAML is a strict superset of JSON—any valid JSON file is also valid YAML. If you're a diehard JSON fan, you can write your stack configurations in JSON and Atmos will parse them just fine. You just lose comments and the cleaner syntax.
YAML Scope is Depth-Relative
The most important thing to understand: there is no file-level scope in Atmos. When you import multiple YAML files, Atmos merges them into a single, unified configuration. The scope is determined by the depth in the YAML tree, not by which file something is defined in.
Think of it like this: Atmos processes all imports and sees one big YAML document. Variables and settings at the same depth in the tree have the same scope.
stacks/globals.yaml
stacks/prod.yaml
After processing, Atmos sees this as one merged configuration:
vars:
environment: production
region: us-east-1
namespace: myapp
components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16"
All three variables (environment, region, namespace) have the same scope—they're all at the top-level vars depth.
Deep Merge: Maps Combine, Values Override
When Atmos processes imports, it deep merges YAML configurations.
Think of it like layering transparencies: maps blend together, but when the same key appears in multiple layers, the top layer wins. It's infrastructure inheritance, YAML style.
Here's how it works:
- Maps (objects) merge recursively - Keys from both maps combine
- Later values override earlier ones - Import order matters
- Lists replace entirely - No list merging, last one wins
stacks/base.yaml
stacks/dev.yaml
Result after merge:
vars:
tags:
ManagedBy: Atmos-Dev # Overridden
Team: Platform # Inherited
Environment: Development # Added
components:
terraform:
vpc:
vars:
enable_dns: true # Inherited
enable_nat: true # Overridden
Import order matters! Atmos processes files sequentially. Later imports override earlier ones.
Dot Notation: Flatten Deep Nesting
When you only need to set one value in a deeply nested section, you don't have to create the full hierarchy. Use dot notation for cleaner, more readable configuration.
Instead of this (verbose nesting):
stacks/dev.yaml
You can write this (dot notation):
stacks/dev.yaml
Both configurations are equivalent, but dot notation is more concise when you're setting single values deep in the tree.
When to Use Dot Notation
✅ Use dot notation when:
- Setting single values in deeply nested structures
- You want more readable configuration
- You're only touching one or two values in a section
❌ Use traditional nesting when:
- Setting multiple values in the same section
- You want to see the full structure at a glance
- You're defining complex nested objects
Example: Mix both approaches
stacks/prod.yaml
Dot notation works anywhere in Atmos YAML—not just in component configuration. Use it in vars, locals, settings, env, or any nested section.
Multi-line Strings: Folding and Literals
YAML provides two powerful ways to handle multi-line strings, which is especially useful for scripts, policies, or long descriptions.
Literal Block (|) - Preserve Line Breaks
The | (pipe) preserves line breaks exactly as written. Each newline in your YAML becomes a newline in the string.
vars:
startup_script: |
#!/bin/bash
echo "Starting application..."
export APP_ENV=production
./start.sh
Result: A string with actual newlines between each line.
Folded Block (>) - Collapse to Single Line
The > (greater-than) folds newlines into spaces, creating a single flowing line. Blank lines create paragraph breaks.
vars:
description: >
This is a very long description that would be hard to read
if it were all on one line. YAML folds these lines into a
single string with spaces between them.
A blank line creates a paragraph break.
Result: "This is a very long description that would be hard to read if it were all on one line. YAML folds these lines into a single string with spaces between them.\nA blank line creates a paragraph break."