What Is YAML?
YAML — originally "Yet Another Markup Language," later backronymed to YAML Ain't Markup Language — is a human-friendly data serialization format designed to be readable to humans and easy to map to data structures across programming languages. First defined by Clark Evans, Ingy döt Net, and Oren Ben-Kiki in 2001, it reached version 1.2.2 in 2021, which aligns YAML's JSON subset interpretation with the JSON specification.
YAML is the dominant configuration format for modern DevOps tooling: Docker Compose, Kubernetes manifests, GitHub Actions, Ansible playbooks, GitLab CI, Helm charts, and countless other systems use YAML as their human interface.
Core Data Model
YAML maps to three fundamental data types:
| YAML term | Equivalent |
|---|---|
| Scalar | String, integer, float, boolean, null, date |
| Sequence | Ordered list (array) |
| Mapping | Key-value pairs (hash/dict/object) |
Every YAML document is either a single node or a collection of nodes forming a directed acyclic graph (the YAML data model supports anchors and aliases that allow graph sharing).
Basic Syntax
# This is a YAML comment
# Scalars
name: Kaiju Converter
version: 2.1.0
active: true
price: 9.99
created: 2024-01-15 # date scalar (!!timestamp in YAML 1.1)
description: null # or ~
# Block sequence (list)
tags:
- converter
- tools
- web
# Inline (flow) sequence
colors: [red, green, blue]
# Block mapping (nested object)
database:
host: localhost
port: 5432
name: kaijudb
options:
ssl: true
timeout: 30
# Inline (flow) mapping
point: {x: 10, y: 20}
Multi-line Strings
YAML has two block scalar styles for multi-line text:
Literal block scalar (|) — preserves newlines:
message: |
Dear user,
Welcome to KaijuConverter.
Enjoy converting files!
Folded block scalar (>) — converts newlines to spaces (like paragraph wrapping):
description: >
This is a long description that
will be folded into a single line
when parsed.
Both support chomping indicators:
|-/>-— strip final newline (strip)|+/>+— keep all trailing newlines (keep)|/>— keep exactly one final newline (clip, default)
Anchors and Aliases
YAML allows reuse of node content without duplication:
defaults: &defaults
image: ubuntu:22.04
restart: always
environment:
- NODE_ENV=production
web:
<<: *defaults
ports:
- "80:3000"
api:
<<: *defaults
ports:
- "8080:8080"
&anchordefines an anchor nameddefaults.*aliasreferences it (the entire mapping is duplicated).<<:is the merge key — merges the referenced mapping into the current one, allowing override.
Anchors resolve a major YAML pain point: DRY configuration without templating engines.
Document Markers and Multiple Documents
A YAML file can contain multiple documents separated by ---:
---
name: document one
---
name: document two
...
--- starts a new document; ... ends one (optional). This is used by Kubernetes to bundle multiple resources in one file and by Ansible for multi-task playbooks.
Type Coercion — The Notorious Problem
YAML 1.1 (used by most libraries before 2021) applies aggressive implicit type coercion:
| Value | YAML 1.1 type | YAML 1.2 type |
|---|---|---|
true, yes, on |
boolean true |
only true is boolean |
false, no, off |
boolean false |
only false is boolean |
null, ~ |
null | null |
1.0 |
float | float |
0755 |
octal 493 |
string "0755" |
0xFF |
hex 255 |
string "0xFF" |
1_000_000 |
integer 1000000 |
string "1_000_000" |
2001-01-23 |
date | string |
NO |
boolean false |
string "NO" |
The Norway Problem: a country code NO parsed as boolean false in YAML 1.1 is the canonical example. Always quote ambiguous values:
country: "NO" # string "NO"
enabled: true # boolean true
octal_mode: "0755" # string "0755", not octal 493
YAML vs. JSON
YAML is a superset of JSON from YAML 1.2 onwards (JSON is valid YAML). Key differences:
| Feature | YAML | JSON |
|---|---|---|
| Comments | Yes (#) |
No |
| Multi-line strings | Yes (literal/folded) | No (escape \n) |
| Trailing commas | Yes | No |
| Unquoted strings | Yes | No |
| Anchors/aliases | Yes | No |
| Multiple documents | Yes | No |
| Verbosity | Low | Medium |
| Parsing complexity | Very high | Low |
| Security | Higher risk | Lower risk |
YAML parsers are notoriously complex — the specification runs to 200+ pages and has numerous edge cases. This complexity has produced security vulnerabilities in several parsers (arbitrary code execution via !!python/object tags).
Security: YAML Deserialization Attacks
YAML supports tags that hint the parser to construct specific objects:
!!python/object/apply:os.system ['rm -rf /']
A YAML parser that allows arbitrary tag construction (PyYAML yaml.load() without Loader) will execute this. Always use safe loaders:
# UNSAFE — never do this with untrusted input
data = yaml.load(untrusted_string)
# SAFE
data = yaml.safe_load(untrusted_string) # Python
data = YAML::safe_load(untrusted_string) # Ruby
In production, use SafeLoader / yaml.safe_load() exclusively. Never expose YAML parsing of untrusted input to a FullLoader or equivalent.
YAML in CI/CD Ecosystems
GitHub Actions:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: npm test
Kubernetes Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kaiju-web
spec:
replicas: 3
selector:
matchLabels:
app: kaiju
template:
spec:
containers:
- name: web
image: kaijuconverter:latest
ports:
- containerPort: 80
Docker Compose:
version: "3.9"
services:
app:
build: .
ports:
- "8080:80"
volumes:
- ./storage:/var/www/storage
depends_on:
- db
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: secret
Linting and Validation
- yamllint: Python-based linter checking syntax, style (indentation, line length, truthy values).
- kubeval / kubeconform: validates Kubernetes YAML against official API schemas.
- JSON Schema: YAML can be validated against JSON Schema via libraries like
jsonschema(Python). - VS Code YAML extension (Red Hat): IntelliSense, schema association, inline errors.
Converting YAML
- YAML → JSON:
yq e -o=json input.yaml, Pythonjson.dumps(yaml.safe_load(f)), oryq(Go version). - YAML → TOML:
yq e -o=toml input.yaml(yq 4.x). - JSON → YAML:
yq e -P input.json(prettify/convert). - YAML → environment variables:
yq e '.database | to_entries | .[] | .key + "=" + .value' config.yaml.
Best Practices
- Always use
safe_loadwhen parsing untrusted input — neverload(). - Quote strings that could be interpreted as booleans, numbers, or dates:
"yes","1.0","2024-01-01". - Use 2-space indentation — tabs are forbidden in YAML and cause parse errors.
- Validate with yamllint in CI before deploying configuration changes.
- Use anchors for repeated blocks instead of copy-pasting.
- Keep documents under 200 lines — split large configs into separate files and include them.
- Add
---at the top of every file to signal it is a YAML document. - Avoid deep nesting — more than 4 levels becomes hard to maintain.
- Use YAML 1.2-compliant parsers to avoid the Norway Problem and other 1.1 coercion surprises.
- Document schema with comments or a companion JSON Schema file.
Related conversions
Frequent conversions across the catalogue: