If you only read one piece on this site about YAML, make it this one. The format looks gentle but hides more edge cases than its friendly face suggests. Below is the syntax reference I keep coming back to, with a working example for every rule.
Indentation: spaces only, and consistent
YAML uses indentation to express nesting, and it accepts spaces only — never a tab. The number of spaces is up to you, but it must be the same at every level.
server:
host: localhost
port: 8080
limits:
cpu: "2"
memory: 4G
Two spaces per level is the community convention. Whatever you pick, hold it steady; an off-by-two indentation is the most common cause of "valid YAML, wrong structure".
Scalars and when to quote
A scalar is any single value. Unquoted scalars are convenient but the parser guesses their type. Quote whenever the value is not a clean number or an obvious boolean:
password: "1234abc" # quote: starts with a digit
version: "1.10" # quote: keep it a string, not 1.1
active: yes # 1.1 parses this as boolean true
path: "C:\temp" # quote: backslash and colon are risky
token: "true" # quote: you want the string, not the boolean
Double quotes support escape sequences (\n, \t); single quotes treat almost everything literally, except that two single quotes represent one. When a value contains :, #, {, }, [, ], , or starts with a special symbol, quote it.
Block scalars and the chomping flag
For multi-line text, YAML offers two block styles and a chomping flag that controls trailing newlines.
|— literal block: every newline is kept.>— folded block: newlines become spaces, good for prose.
The chomping flag sits after the symbol:
| Indicator | Name | Trailing newline behaviour |
|---|---|---|
| / > | clip (default) | Exactly one trailing newline kept |
|- / >- | strip | All trailing newlines removed |
|+ / >+ | keep | All trailing newlines retained |
Here are the three chomping variants side by side:
clip: |
one
two
strip: >-
one
two
keep: >+
one
two
Read that carefully. clip ends with a single newline; strip ends with none; keep preserves the two blank lines after "two". This is the detail most tutorials skip, and it is exactly what breaks a heredoc or a certificate when you paste it back out.
Flow style: JSON-like inline writing
When a structure is small, you can write it on one line, flow style:
person: { name: devtul, roles: [admin, dev] }
matrix:
- { a: 1, b: 2 }
- { a: 3, b: 4 }
Flow style is valid YAML everywhere, which is why JSON pasted into YAML still parses. Use it for compact values, block style for anything a human reads.
Anchors and aliases: define once, reuse many
Define a chunk with an anchor (&name) and reference it with an alias (*name):
defaults: &base
adapter: postgres
pool: 5
production:
<<: *base
database: prod
pool: 20
The alias *base pulls in the whole defaults mapping. The merge key << is the special key that says "merge that anchored mapping into this one" — here adapter and pool are inherited, then pool is overridden to 20. Anchors cut duplication in large configs, but they also hide where a value came from, so use them where repetition is real.
Multiple documents in one file
A single .yml file can hold several documents, separated by --- and optionally closed with ...:
---
name: first
value: 1
---
name: second
value: 2
...
This is how Kubernetes reads a directory of manifests, and how some CI systems stack jobs. Not every parser exposes multiple documents, but the syntax is core YAML.
Explicit type tags
If inference is not enough, force a type with a tag:
code: !!str 1234 # always the string "1234"
ratio: !!float 1 # the number 1.0
missing: !!null nil # explicit null
Tags start with !! for the standard schema. They are the escape hatch when quoting still leaves the parser guessing.
Comments
Anything after # on a line is a comment, and it is stripped from the data:
port: 8080 # local dev only
# debug: true # commented out entirely
Comments are the reason YAML won the config-file war over JSON. Use them to record why a value is what it is; six months from now that context is worth more than the value.
Put it together and verify
None of the above is useful if a typo silently reshapes your data. After writing a file, open the YAML viewer and check the parsed tree — particularly that your block scalars and anchors resolved the way you meant.