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:

yaml
# 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 value

Geen 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.

yaml
# 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 YAML
Het Noorwegen-probleem: In YAML 1.1 (gebruikt door PyYAML, veel oudere tools) worden de ongenoteerde waarden yes, 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
# 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 float

Sequences: lijsten in YAML

Lijsten gebruiken een koppelteken-spatie-prefix. Elk item kan een scalar, een mapping of een andere sequence zijn:

yaml
# 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:

yaml
# 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 two

De |-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

YAML verbiedt tabs voor inspringing. Volledig. Als je editor een tab-teken invoegt in de inspringing van een YAML-bestand, zal het bestand ofwel niet worden geparsed of — erger — onjuist worden geparsed. Configureer je editor om spaties te gebruiken voor .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:

yaml
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 build

Echt voorbeeld: Kubernetes Deployment-manifest

yaml
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:

python
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:

js
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.