Skip to content
d.devtul.fun
中文
Config · 2026-08-12

YAML Syntax Guide: Every Directive and Edge Case You Need to Know

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:

IndicatorNameTrailing newline behaviour
| / >clip (default)Exactly one trailing newline kept
|- / >-stripAll trailing newlines removed
|+ / >+keepAll 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.

Keep reading