Saltar al contenido principal

YAML Basics

YAML is an indentation-scoped data format standardised as YAML 1.2, built for configuration files that humans write and programs read. Nesting comes from spaces instead of braces, bare scalars are typed by inference, and comments start with #. Those three conveniences cause almost every real-world YAML bug, so this guide teaches rules and gotchas together.

Solo local

La guía de abajo solo está disponible en inglés.

YAML Basics explained

YAML is the format configuration arrives in. Kubernetes manifests, GitHub Actions workflows, docker-compose files and Ansible playbooks are all YAML: nested maps written with spaces, lists written with dashes, hardly a bracket in sight. The name originally meant Yet Another Markup Language; the authors recast it as YAML Ain't Markup Language — the more accurate reading, since it describes data, not documents.

The current standard is YAML 1.2 (2009), and its most important change is quiet: 1.1 typed the bare words yes, no, on and off as booleans, and 1.2 does not. Most software still loads 1.1 rules by default, so the same line of text can mean different things in different tools. YAML 1.2 also made almost all JSON documents valid YAML — the cleanest one-sentence summary of the grammar.

This guide covers what a newcomer needs — indentation rules, scalar typing, quoting, block scalars, anchors and comments — and ends with an exact list of what this site's converters accept and refuse. Everything runs in your browser, nothing is uploaded, so the examples can be pasted in and prodded safely.

Because YAML 1.2 treats most JSON documents as valid YAML, any config you can simplify down to braces gets instant tooling: paste it into the JSON Formatter and it will pretty-print, validate, and report the exact line and column of every syntax error.

When a brand-new file could honestly go either way, the JSON vs YAML comparison puts the trade-offs into one decision table and tells you which format each kind of document wants.

Indentation is the syntax

In YAML, whitespace is not decoration — it is the entire structure. A mapping is a key, a colon, a space, then a value; a nested value is written on the next line, indented further, and two lines at the same indentation are siblings. Tabs are forbidden outright: the spec cannot decide how wide a tab is, so parsers reject them instead of guessing. Editors keep inserting tabs on copy-paste, which is why so many files look perfect and refuse to parse.

The convention is two spaces per level. Four or six are equally valid — the spec only forbids tabs — but two is what Kubernetes and Compose use, what every linter expects, and what keeps deep manifests from scrolling sideways. Mixing widths inside one file is how indentation errors are born, so pick two and let the editor enforce it.

  • One level = any fixed space count; two is the convention.
  • Tabs in indentation are rejected by parsers, not converted.
  • A sequence item may sit at its parent key's indent — the dash is the marker.
  • Values can also be written inline in flow style: ports: [8080].

A nested mapping with a sequence

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  cache:
    image: redis:7

The tree a parser builds

services
├─ web
│  ├─ image: "nginx:1.27"
│  └─ ports: ["8080:80"]
└─ cache
   └─ image: "redis:7"

Scalars and the Norway problem

Quoted values are strings, always. Unquoted values are typed by inference, and inference is where YAML's reputation comes from: a bare 8080 becomes the number 8080 and an empty value becomes null, which helps — until inference types something you meant as text, like a country code or a version string.

The classic failure is a list of ISO country codes in which NO — Norway — parses as boolean false: the Norway problem, funny until it silently disables a deployment flag. Version 1.1 went much further, as the table shows. The 1.2 core schema resolves only true and false as booleans and reads the rest of the table below as plain strings or decimal numbers — but because so much deployed software still applies 1.1 rules, the defensive habit is to quote anything that must stay a string.

You wroteYAML 1.1 parses it asYAML 1.2 core schema parses it as
noboolean falsethe string "no"
on / offboolean true / falsethe strings "on" / "off"
12:30integer 750 (sexagesimal)the string "12:30"
0640integer 416 (octal)integer 640 (decimal)
2026-09-19a date objectthe string "2026-09-19"
~nullnull

Quoting and block scalars

YAML offers three ways to write a string. Unquoted is the default and fine for most values. Single quotes are literal — the only escape is doubling a quote ('it''s fine'). Double quotes support backslash escapes like \n and \t, the style JSON uses. The defensive rule carries over: if a value contains anything that could be mistaken for structure — colons, hashes, reserved words — quote it deliberately.

Multi-line text gets block scalars. A literal block, written |, keeps every newline exactly as typed — the right shape for shell scripts and certificates. A folded block, written >, joins lines into one flowing paragraph — the right shape for a long description. Both take a chomping indicator: |- strips the final newline, |+ keeps every trailing one, and plain | keeps exactly one.

Two block scalar styles

script: |
  set -e
  make build
  make deploy

summary: >
  Deploys finish
  in under a minute.

What the scalars resolve to

script:   "set -e\nmake build\nmake deploy\n"
summary:  "Deploys finish in under a minute.\n"

Anchors, aliases and reuse

YAML lets one node carry a name other nodes reference. Write &name after a key to anchor its value; write *name anywhere else to alias it, and the parser substitutes a copy of the anchored node. Jobs sharing one retry policy then point at a single definition, and the change lands once.

Two extensions ride on this mechanism. Merge keys, written <<: *name, splice every key of an anchored mapping into the current one — common in Compose and Ansible files, and a 1.1-era convention that never entered the 1.2 core grammar. Anchors can also be abused: aliases nested inside aliases let ten definitions expand to a million nodes — the billion-laughs attack — so parsers you trust budget expansion and report the cap rather than hang.

An anchor and two aliases

defaults: &base
  retries: 3
  timeout: 30s

staging:
  retries: 3
  timeout: 30s
  log: *base

What a consumer receives

defaults:  { retries: 3, timeout: "30s" }
log alias: { retries: 3, timeout: "30s" }   (staging.log)

Comments and multiple documents

Comments start with # and run to the end of the line; a hash inside a quoted string does not count. This is YAML's biggest ergonomic win over JSON, which removed comments by design, and the reason human-maintained config gravitates here: the file explains itself inline, and reviews quote a line and its comment in one diff hunk.

One file may also hold several documents, separated by lines of three dashes; a leading --- is the optional start marker and ... ends a document. This is how one artifact carries a staging config and a production config side by side. This site's converters parse every document and operate on the last one, matching common CLI behaviour.

Two documents, one file

env: staging
region: eu-1
---
env: production
region: us-2

What the converters use

env: production
region: us-2   (the last document)

What this site's converters accept

Every YAML parser is a parser of a subset — the full 1.2 grammar is famously large — and a converter earns trust by stating its subset instead of letting you discover it by failure. This site's YAML library implements the 1.2 core schema over the block and flow constructs that appear in real configuration files, with deliberate limits where the spec allows unbounded work. The table is the contract.

FeatureStatus hereBehaviour
Block mappings and sequencesAcceptedNested to any depth, two spaces or any consistent indent
Flow style [1, 2] and {a: 1}AcceptedIncluding whole JSON documents pasted as-is
Comments and quoted scalarsAcceptedBoth quote styles, all block scalar styles
Tabs in indentationRefusedRejected with the offending line number
Explicit keys (? key)RefusedNo JSON equivalent — JSON keys must be strings
Merge keys (<<)RefusedExpand the merge by hand, or alias values directly
%YAML 1.1 directiveWarnedThe 1.2 core schema is applied; yes and no stay strings
Multiple documentsParsedConverters operate on the last document
Alias expansionBudgetedDeep alias chains are capped and reported, never unrolled

Frequently asked questions

Is my YAML uploaded when I use these converters?

No. Every converter on this site runs as JavaScript inside your browser tab; there is no upload step and no backend to receive one. Verify it in DevTools: open the Network panel, convert a file, and watch the request list stay empty. The site's Content-Security-Policy also blocks outbound connections from page scripts.

Why does my file fail to parse when it looks right?

Three culprits cover most cases: a tab hiding in the indentation (parsers refuse tabs outright), a YAML 1.1-ism such as a bare no or a merge key that a 1.2 parser will not guess at, or an unquoted scalar that inference typed into something you did not mean. A good converter names the line; this site's does.

Is YAML a superset of JSON?

In YAML 1.2, mostly yes: a JSON document with its braces and brackets intact parses as YAML unchanged. The reverse is never true. Comments, anchors, bare keys, multi-line block scalars and multiple documents in one file have no JSON representation, so converting YAML to JSON is a one-way door for any file that uses them.

How do I avoid the Norway problem?

Quote every scalar whose type you care about. A bare NO parses as boolean false under YAML 1.1 rules, and on, off, yes and no follow it; the 1.2 core schema keeps them strings, but much deployed software still loads 1.1. Quoting country codes, feature flags and version strings is the zero-cost habit.

Should I use anchors or just repeat the values?

Repeat values when the copies may drift apart; anchor and alias them when they are genuinely one fact defined once. Anchors keep config DRY but cost local readability — a reader must jump to the definition. Merge keys are the least portable part: many parsers, including this site's converters, refuse them rather than guess the splice order.

Two spaces or four spaces for YAML indentation?

Both are valid — the spec forbids tabs, not any space count — so this is convention, not correctness. Two spaces won: Kubernetes and Compose use it, every linter defaults to it, and deep nesting stays readable. What matters is never mixing widths in one file.