Als je ooit een Kubernetes-cluster hebt beheerd, een GitHub Actions-workflow hebt opgezet, of een Docker Compose-bestand hebt geschreven, heb je al YAML geschreven — waarschijnlijk heel veel. YAML is het configuratieformaat dat de meeste moderne DevOps-tooling aandrijft. Maar ondanks dat het overal is, is het een formaat dat mensen voortdurend verrast. Ik heb meer dan mijn deel van YAML-indentatiefouten gedebugd om 23:00 met een geblokkeerde deploy. Laten we zorgen dat jij dat niet hoeft te doen.
YAML staat voor YAML Ain't Markup Language — ja, het is een recursief acroniem. Oorspronkelijk was het "Yet Another Markup Language" maar het werd hernoemd om te benadrukken dat het een dataserialisatieformaat is, geen document-opmaaktaal. De YAML 1.2-specificatie is de huidige standaard, hoewel veel tools nog steeds YAML 1.1 implementeren, dat enkele echt gevaarlijke verschillen heeft die we hieronder behandelen.
De basis: YAML-syntaxis in één oogopslag
YAML gebruikt inspringing (alleen spaties — nooit tabs) om structuur uit te drukken. Een YAML-document is een mapping (sleutel-waardeparen), een sequence (een lijst) of een scalar (een enkelvoudige waarde). Hier is een echte Kubernetes-stijl configuratie die alle essentials behandelt:
# This is a comment — YAML supports them, JSON does not
app:
name: payment-service
version: "2.1.0" # quoted to keep it a string
port: 8080
debug: false
timeout: 30.5
tags:
- payments
- backend
- critical
database:
host: postgres.internal
port: 5432
ssl: true
password: null # explicitly no valueGeen accolades, geen aanhalingstekens bij de meeste strings, geen komma's. Voor een bestand dat mensen elke dag bewerken, telt die duidelijkheid snel op. Maar YAML betaalt voor die leesbaarheid met complexiteit — er gebeurt veel onder de motorkap.
Scalaire typen: strings, getallen, booleans, null
YAML leidt typen af uit het uiterlijk van de waarde. Dit is de meeste tijd handig en stilzwijgend catastrofaal in een paar specifieke gevallen.
# Strings — quotes are optional unless value is ambiguous
name: Alice
greeting: "Hello, world"
message: 'single quotes work too'
path: /usr/local/bin # unquoted — still a string
# Numbers
integer: 42
negative: -7
float: 3.14159
scientific: 6.022e23
# Booleans
ssl_enabled: true
verbose: false
# Null
api_key: null
legacy_field: ~ # tilde is also null in YAMLyes, no, on, off, true, false,
y, n, Y, N — en hun varianten in hoofdletters —
allemaal geparsed als booleans. Dit betekent dat de ISO-landcode NO (Noorwegen) boolean
false wordt. YAML 1.2 heeft dit verholpen. Plaats altijd aanhalingstekens bij strings die op booleans lijken. Zie de
Wikipedia-pagina over het Noorwegen-probleem
voor het volledige verhaal.# YAML 1.1 implicit type coercion — these silently become booleans:
country: NO # → false (Norway Problem!)
enabled: yes # → true
toggle: on # → true
# The fix: always quote when there's any ambiguity
country: "NO"
enabled: "yes"
version: "1.0" # also quote version numbers — 1.0 would be a floatSequences: lijsten in YAML
Lijsten gebruiken een koppelteken-spatie-prefix. Elk item kan een scalar, een mapping of een andere sequence zijn:
# Simple list
languages:
- Python
- Go
- TypeScript
# List of objects (common in Kubernetes)
containers:
- name: api
image: my-api:latest
port: 8080
- name: sidecar
image: envoy:v1.28
port: 9901
# Inline flow style (valid YAML, less readable)
tags: [payments, backend, v2]Meerdere regels strings: literal block vs. folded
Hier overtreft YAML JSON voor configuratiebestanden. Twee speciale operators verwerken strings met meerdere regels op een elegante manier:
# Literal block scalar (|) — preserves newlines exactly
startup_script: |
#!/bin/bash
set -e
echo "Starting service..."
npm start
# Folded scalar (>) — folds newlines into spaces (good for long descriptions)
description: >
This service handles payment processing
for all regions. It connects to Stripe
and falls back to PayPal.
# Result: "This service handles payment processing for all regions. It connects to Stripe and falls back to PayPal."
# Chomp modifiers
keep_trailing: |+
line one
line two
strip_trailing: |-
line one
line twoDe |-operator is wat de meerregelige run:-scripts van GitHub Actions
leesbaar maakt. Het cheatsheet van yaml-multiline.info
is de snelste manier om te onthouden welke chomp-modifier wat doet. Zonder deze blokscalars zou je
escaped newlines in één string moeten schrijven — wat JSON je dwingt te doen.
Tabs vs spaties — de kardinale regel
.yml- en .yaml-bestanden. Twee spaties is de
vrijwel universele conventie.Dit is de belangrijkste oorzaak van cryptische YAML-fouten. Een tab ziet er in de meeste editors identiek uit aan spaties. Schakel "whitespace-tekens weergeven" in je editor in bij het debuggen van YAML, of plak je bestand in de YAML Validator voor een duidelijke foutmelding die naar de exacte regel wijst.
Echt voorbeeld: GitHub Actions-workflow
Hier is een echt GitHub Actions-workflowfragment. Let op hoe het meerregelige run:-blok
de literal block scalar gebruikt, en hoe inspringing de structuur bepaalt:
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: |
npm run lint
npm run test -- --coverage
npm run buildEcht voorbeeld: Kubernetes Deployment-manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
namespace: production
labels:
app: payment-api
version: "2.1.0"
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: api
image: payment-api:2.1.0
ports:
- containerPort: 8080
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"YAML parsen in Python en JavaScript
In Python is de PyYAML-bibliotheek
de standaardkeuze. Gebruik altijd safe_load(), niet load() — de onveilige versie
kan willekeurige Python-code uitvoeren vanuit een YAML-bestand:
import yaml
# Reading a YAML config file
with open('config.yaml', 'r') as f:
config = yaml.safe_load(f)
print(config['app']['name']) # payment-service
print(config['app']['port']) # 8080 (integer, not string)
print(config['app']['tags']) # ['payments', 'backend', 'critical']
# Writing Python data to YAML
data = {
'service': 'auth-api',
'replicas': 2,
'endpoints': ['/login', '/logout', '/refresh']
}
with open('output.yaml', 'w') as f:
yaml.dump(data, f, default_flow_style=False)In JavaScript/Node.js is js-yaml de meestgebruikte bibliotheek:
import yaml from 'js-yaml';
import fs from 'fs';
// Parse YAML string
const raw = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(raw);
console.log(config.app.name); // payment-service
console.log(config.app.tags); // ['payments', 'backend', 'critical']
// Dump an object to YAML string
const output = yaml.dump({
name: 'my-service',
port: 3000,
tags: ['api', 'public']
});
console.log(output);Samenvatting
De inspringing-gebaseerde syntaxis van YAML, ondersteuning voor commentaar en leesbare meerregelige strings maken het de juiste keuze voor configuratiebestanden die mensen schrijven en onderhouden. Maar het brengt echte valkuilen met zich mee: het Noorwegen-probleem, tab/spatie-verwarring en impliciete typecoercering van YAML 1.1-parsers. Ken de regels, citeer alles wat ambigu is, configureer je editor om witruimte te tonen, en gebruik een YAML Formatter om bestanden consistent te houden. YAML is een krachtige tool als je eenmaal begrijpt waar het bijt.