DevBolt
·10 min read

YAML Syntax Guide: From Basics to Gotchas

YAMLDevOpsReference

YAML ("YAML Ain't Markup Language") is the configuration language of modern DevOps. Kubernetes manifests, GitHub Actions workflows, Docker Compose files, Ansible playbooks — they all use YAML. This guide covers the syntax, common pitfalls, and the tricky edge cases that trip up even experienced developers.

YAML Basics

YAML uses indentation (spaces, never tabs) to represent structure. At its core, everything is either a mapping (key-value pair), a sequence (list), or a scalar (string, number, boolean).

YAML
# This is a comment

# Mapping (key: value)
name: DevBolt
url: https://devbolt.dev
port: 3000

# Sequence (list)
tools:
  - JSON Formatter
  - Base64 Encoder
  - Hash Generator

# Nested mapping
database:
  host: localhost
  port: 5432
  credentials:
    user: admin
    password: secret

Data Types

YAML auto-detects types. This is powerful but also the source of many bugs:

YAML
# Strings
name: hello              # unquoted
name: "hello world"      # double-quoted (supports escapes)
name: 'hello world'      # single-quoted (literal)

# Numbers
count: 42                # integer
price: 19.99             # float
hex: 0xff                # hexadecimal
octal: 0o755             # octal

# Booleans
enabled: true
disabled: false

# Null
value: null
also_null: ~
also_null_2:             # empty value = null

# Dates
created: 2026-03-18
timestamp: 2026-03-18T14:30:00Z

The Norway Problem (and Other Type Gotchas)

YAML's auto-typing is its most notorious footgun. Country codes, version numbers, and other values can be silently interpreted as the wrong type:

Dangerous YAML
# These are all interpreted as booleans (true/false):
country: NO           # false (not the string "NO"!)
answer: yes           # true
flag: off             # false
confirm: on           # true

# These are interpreted as numbers:
version: 1.0          # float 1.0 (not string "1.0")
zipcode: 01onal           # octal 1 (not string "01")
build: 3.10           # float 3.1 (not string "3.10")

# Fix: always quote ambiguous values
country: "NO"
version: "1.0"
zipcode: "01234"
build: "3.10"

This is called the Norway problem. The country code "NO" becomes boolean false. The fix is simple: quote any value that could be misinterpreted.

Multiline Strings

YAML has two multiline operators. This is one of its most useful features:

YAML
# Literal block (|) — preserves newlines exactly
script: |
  #!/bin/bash
  echo "Hello"
  echo "World"
# Result: "#!/bin/bash\necho \"Hello\"\necho \"World\"\n"

# Folded block (>) — joins lines with spaces (like HTML)
description: >
  This is a long
  description that will
  be folded into one line.
# Result: "This is a long description that will be folded into one line.\n"

# Strip trailing newline with "-"
script: |-
  echo "no trailing newline"
# Result: "echo \"no trailing newline\""

# Keep trailing newlines with "+"
script: |+
  line one
  line two

# Result: "line one\nline two\n\n"

Use | (literal) for shell scripts, SQL, and code where newlines matter. Use > (folded) for long descriptions and prose.

Anchors and Aliases

Avoid repetition with anchors (&) and aliases (*):

YAML
# Define an anchor
defaults: &defaults
  timeout: 30
  retries: 3
  log_level: info

# Reuse with alias
development:
  <<: *defaults
  log_level: debug    # override one value

production:
  <<: *defaults
  timeout: 60         # override one value

# Without anchors, you'd repeat all three values twice

The << merge key injects all key-value pairs from the anchor. Any keys you define after the merge override the anchored values.

Multi-Document Files

A single YAML file can contain multiple documents, separated by ---. This is commonly used in Kubernetes:

YAML
# Document 1: Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
---
# Document 2: Service
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP
  ports:
    - port: 80

Flow Style (Inline Syntax)

YAML supports a compact JSON-like syntax for short values:

YAML
# Flow mapping (inline object)
point: {x: 10, y: 20}

# Flow sequence (inline array)
colors: [red, green, blue]

# Mixed
servers:
  - {host: web1, port: 80}
  - {host: web2, port: 80}

# Equivalent block style:
servers:
  - host: web1
    port: 80
  - host: web2
    port: 80

Flow style is great for short, simple data. For anything complex, stick with block style for readability.

YAML vs JSON vs TOML

FeatureYAMLJSONTOML
CommentsYesNoYes
Multiline stringsYes (| and >)NoYes (triple quotes)
References/anchorsYesNoNo
ReadabilityHighMediumHigh
Parsing safetyRisky (type coercion)SafeSafe
Common useK8s, CI/CD, AnsibleAPIs, package.jsonCargo.toml, pyproject

Real-World Examples

GitHub Actions Workflow

.github/workflows/ci.yaml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test

Docker Compose

See our Docker Compose guide for a deep dive. Here's the basic structure:

compose.yaml
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - api

  api:
    build: ./api
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/app

Kubernetes Deployment

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: myapp:1.2.3
          ports:
            - containerPort: 8080
          resources:
            limits:
              memory: "256Mi"
              cpu: "500m"

Common Mistakes

  • Using tabs for indentation. YAML only allows spaces. A single tab will cause a parse error. Configure your editor to insert spaces when you press Tab in YAML files.
  • Not quoting ambiguous values. Values like NO, yes, 1.0, on, and off are interpreted as booleans or numbers. Always quote strings that could be misinterpreted.
  • Inconsistent indentation. YAML doesn't mandate a specific indent size, but mixing 2-space and 4-space indentation in the same file will cause confusion (and often errors). Pick 2 spaces and stick with it.
  • Duplicate keys. YAML silently allows duplicate keys — the last one wins. This can cause hard-to-find bugs when you accidentally define the same key twice in a large file.
  • Forgetting the space after colons. key:value is a string, not a mapping. You need a space: key: value.

Running YAML in production?

If you're deploying Kubernetes manifests, DigitalOcean Kubernetes offers managed clusters with free control plane, automatic upgrades, and simple pricing. Great for teams that want K8s without the infrastructure overhead.

Try It Yourself

Use our YAML Validator & Formatter to validate and format your YAML files. Need to convert between formats? The JSON ↔ YAML Converter handles that instantly. And if you're working with Kubernetes, our Kubernetes YAML Validator checks for resource-specific issues beyond basic syntax.