YAML is everywhere in modern infrastructure: Kubernetes manifests, GitHub Actions workflows, Docker Compose files, Ansible playbooks, Helm charts. It is also one of the easiest formats to break silently — a two-space indent that becomes three spaces, a missing colon, or a bare string that gets coerced to a boolean. A YAML validator online catches these issues at the source, before they cause a failed deployment or a cryptic runtime error.

Validate your YAML now →

Why YAML Validation Matters

YAML parsers are famously lenient. A malformed YAML file often parses without error but produces unexpected data structures. Consider:

# Intended: a list of two strings
fruits:
  - apple
  - orange
  
vegetables:
- carrot  # Accidentally de-indented — still valid YAML but wrong structure
  - spinach

This parses without throwing an error in many parsers, but the resulting structure is not what you intended. Validation tools that perform structural analysis — not just syntax checking — catch this class of bug.

The more dangerous case is YAML’s infamous implicit type coercion in YAML 1.1 (used by PyYAML and many Kubernetes tools until recently):

settings:
  debug: yes        # parsed as boolean true, not string "yes"
  version: 1.0      # parsed as float, not string
  country: NO       # Norway's country code — parsed as boolean false!
  octal: 0777       # parsed as octal integer 511, not string "0777"

A validator with type preview shows you exactly what type each value resolves to, eliminating surprises.

YAML Syntax Fundamentals

Scalars

string: Hello World
quoted_string: "Hello\nWorld"  # supports escape sequences
single_quoted: 'No escape \n here'  # literal backslash
integer: 42
float: 3.14
boolean_true: true
boolean_false: false
null_value: null
multiline: |
  Line one
  Line two
  Line three
folded: >
  These lines
  will be joined
  into one.

The | (literal block) preserves newlines. The > (folded block) replaces newlines with spaces.

Sequences (Lists)

# Block style (most common)
fruits:
  - apple
  - banana
  - cherry

# Flow style (compact)
colors: [red, green, blue]

Mappings (Objects)

# Block style
server:
  host: localhost
  port: 8080
  tls: true

# Flow style
point: {x: 1, y: 2}

Nested Structures

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    environment:
      - NGINX_HOST=example.com
      - NGINX_PORT=80
    volumes:
      - ./html:/usr/share/nginx/html:ro
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret

Anchors and Aliases

YAML supports DRY through anchors (&) and aliases (*):

defaults: &defaults
  adapter: postgres
  encoding: utf8
  pool: 5

development:
  <<: *defaults
  database: myapp_development

production:
  <<: *defaults
  database: myapp_production
  pool: 20

The <<: merge key expands the referenced anchor into the current mapping.

Multi-Document Files

A single YAML file can contain multiple documents separated by ---:

---
kind: Deployment
metadata:
  name: web
---
kind: Service
metadata:
  name: web-svc

Common YAML Errors

Indentation Errors

YAML uses spaces (never tabs) for indentation, and the indent level must be consistent:

# Wrong — mixed indentation
server:
  host: localhost
    port: 8080  # over-indented; parser error

# Correct
server:
  host: localhost
  port: 8080

Missing Colon After Key

# Wrong
server
  host: localhost

# Correct
server:
  host: localhost

Colon in Unquoted String

# Wrong — parser treats this as a key-value pair
message: Error: something went wrong

# Correct
message: "Error: something went wrong"

Tab Characters

# Wrong — YAML forbids tabs for indentation
server:
	host: localhost  # tab character causes parse error

Duplicate Keys

# Technically invalid but silently accepted by many parsers
config:
  timeout: 30
  timeout: 60  # overwrites the first value

YAML 1.1 Boolean Trap

# These are all booleans in YAML 1.1 (PyYAML, Ruby Psych < 4.0):
# true: true, True, TRUE, yes, Yes, YES, on, On, ON
# false: false, False, FALSE, no, No, NO, off, Off, OFF

country_code: NO   # Parses as false, not the string "NO"
enabled: yes       # Parses as true — usually fine, but surprising

# Safe: always quote ambiguous values
country_code: "NO"

YAML 1.2 (used by newer tools) eliminated most of these coercions. Know which version your parser uses.

Validating YAML in CI/CD

yamllint

yamllint is the standard Python-based YAML linter:

pip install yamllint
yamllint config.yaml

With a custom config (.yamllint):

extends: default
rules:
  line-length:
    max: 120
  truthy:
    allowed-values: ['true', 'false']
    check-keys: false
yamllint -c .yamllint .  # lint all YAML files in the repo

GitHub Actions Integration

name: Lint YAML
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install yamllint
        run: pip install yamllint
      - name: Lint YAML files
        run: yamllint .

Pre-commit Hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/adrienverge/yamllint
    rev: v1.35.1
    hooks:
      - id: yamllint
        args: [-c=.yamllint]

Parsing YAML in Code

Python

pip install pyyaml
import yaml

# Load (use safe_load to prevent arbitrary code execution)
with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['server']['host'])

# Validate by catching exceptions
try:
    with open('config.yaml', 'r') as f:
        data = yaml.safe_load(f)
    print("Valid YAML")
except yaml.YAMLError as e:
    print(f"Invalid YAML: {e}")

Node.js

npm install js-yaml
const yaml = require('js-yaml');
const fs = require('fs');

try {
  const config = yaml.load(fs.readFileSync('config.yaml', 'utf8'));
  console.log(config);
} catch (e) {
  console.error('Invalid YAML:', e.message);
}

Go

go get gopkg.in/yaml.v3
package main

import (
    "fmt"
    "log"
    "os"

    "gopkg.in/yaml.v3"
)

type Config struct {
    Server struct {
        Host string `yaml:"host"`
        Port int    `yaml:"port"`
    } `yaml:"server"`
}

func main() {
    data, err := os.ReadFile("config.yaml")
    if err != nil {
        log.Fatal(err)
    }

    var config Config
    if err := yaml.Unmarshal(data, &config); err != nil {
        log.Fatalf("Invalid YAML: %v", err)
    }

    fmt.Printf("Host: %s, Port: %d\n", config.Server.Host, config.Server.Port)
}

YAML vs JSON vs TOML

FeatureYAMLJSONTOML
CommentsYes (#)NoYes (#)
Multiline stringsYes (`, >`)Escaped \n
Anchors/aliasesYesNoNo
Type inferenceImplicit (dangerous)ExplicitStrict
Indentation-basedYesNoNo
Tabs allowedNoN/ANo
Parse ambiguityHigh (1.1) / Low (1.2)LowLow
VerbosityLowMediumLow

YAML’s primary advantage is human readability and low verbosity. Its primary risk is implicit type coercion and indentation-sensitive parsing. For machine-generated config (API responses, build artifacts), prefer JSON. For human-authored config with comments, YAML or TOML are both good choices — TOML is strictly less ambiguous.

Online YAML Validator

For quick syntax checking and structure inspection without running any tools locally, ZeroTool’s YAML validator runs entirely in your browser:

  • Validates YAML syntax with line and column error reporting
  • Shows the parsed structure as a tree
  • Exports validated YAML as JSON
  • 100% local processing — no data is sent to any server

Try the YAML validator →