YAML Patterns
YAML patterns and idioms for infrastructure as code - scalar types, block scalars, anchors, merge keys, and validation.
Scalar Types
# Plain (unquoted) - works most of the time
name: web-01
# Double-quoted - escape sequences work (\n, \t, \\)
message: "Line one\nLine two"
# Single-quoted - literal, no escaping
path: '/etc/nginx/nginx.conf'
# GOTCHA: these are NOT strings without quotes
yes_bool: true # boolean
no_bool: false # boolean
number: 42 # integer
float: 3.14 # float
null_val: null # null
also_null: ~ # null
version: "3.10" # string (quoted to prevent float interpretation)
port: "8080" # string (quoted to prevent integer)
force_string: !!str 123
force_int: !!int "42"
force_float: !!float "3.14"
force_bool: !!bool "true"
GOTCHA: YAML interprets yes, no, on, off as booleans. Quote them: "yes".
Block Scalars
script: |
#!/bin/bash
echo "Line 1"
echo "Line 2"
exit 0
description: >
This is a very long description
that gets folded into a single line.
This starts a new paragraph.
# Keep trailing newline (default)
keep: |
text
# Strip trailing newline
strip: |-
text
# Keep all trailing newlines
chomp: |+
text
PATTERN: | for scripts and multi-line commands. > for long descriptions.
Anchors & Merge Keys
defaults: &defaults
adapter: postgres
host: localhost
port: 5432
development:
database: myapp_dev
<<: *defaults
production:
database: myapp_prod
<<: *defaults
host: db.prod.internal # Override merged value
base_port: &port 8080
services:
web:
port: *port # 8080
api:
port: *port # 8080
common: &common
restart: always
logging:
driver: json-file
resources: &resources
deploy:
resources:
limits:
memory: 512M
web:
<<: [*common, *resources]
image: nginx:latest
GOTCHA: Anchors are a YAML feature, not specific to any tool. They work in Ansible, Docker Compose, CI configs.
Multi-Document YAML
---
apiVersion: v1
kind: Namespace
metadata:
name: app
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: app
data:
key: value
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: app
# Split into individual documents
yq eval-all 'select(documentIndex == 0)' multi.yml
# Count documents
yq eval-all '[.] | length' multi.yml
# Apply all Kubernetes resources
kubectl apply -f multi.yml
USE CASE: Kubernetes manifests, Ansible playbooks with multiple plays.
Validation & Linting
# With yq
yq eval '.' config.yml > /dev/null
# With Python
python3 -c "import yaml; yaml.safe_load(open('config.yml'))"
# With yamllint
yamllint config.yml
yamllint -d '{extends: default, rules: {line-length: {max: 120}}}' config.yml
# YAML to JSON
yq eval -o=json config.yml
# JSON to YAML
yq eval -P config.json
# Validate Ansible playbook
ansible-playbook --syntax-check site.yml
PATTERN: Validate YAML in CI before applying: yamllint && ansible-lint && ansible-playbook --syntax-check.
Quick Reference
| Pattern | Description |
|---|---|
|
Define and reference an anchor |
|
Merge key (inherit from anchor) |
|
Literal block scalar (preserves newlines) |
|
Folded block scalar (joins lines) |
|
Strip trailing newline from block |
|
Force type to string |
|
Document separator (multi-doc) |
|
Explicit null value |
|
Flow mapping (inline dict) |
|
Flow sequence (inline list) |