YAML indentation rules
Whitespace is syntax in YAML. These are the rules, why tabs fail, and the list alignment mistake almost everyone makes at least once.
The rules
- Spaces only. Tab characters are forbidden in indentation. This is not a style preference — the specification prohibits it and every parser rejects it.
- Two spaces per level is the near-universal convention. Four is legal. One is legal and unreadable. What matters is that it is consistent within a file.
- Siblings share a column. Every key in the same mapping must start at exactly the same column. Off by one is a different mapping or an error.
- Children indent further than their parent. Any amount further, as long as it is consistent among the siblings.
- The hyphen counts as indentation for anything on the same line as it, which is why nested keys under a list item line up with the first character after the hyphen and the space.
Why tabs fail, and how to stop it
A file indented with tabs looks perfectly aligned in your editor and fails to parse with a message about a tab character not being allowed. The reason the spec forbids them is that tab width is a display setting, so a tab-indented document would nest differently depending on who opened it.
Fix it once, in your editor config:
# .editorconfig
[*.{yml,yaml}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
To find existing tabs: grep -Pn '\t' config.yaml. To fix the whole
file at once, paste it into the YAML formatter, which
re-emits it with consistent spaces.
Where list items go
Both of these are valid and mean exactly the same thing:
ports:
- 8080
- 9090ports:
- 8080
- 9090The indented form is what Kubernetes, Ansible, and GitHub Actions documentation uses, and it makes the parent-child relationship visible at a glance. Pick it, and be consistent — mixing both in one file is legal and confusing.
Objects inside a list
The keys of a list item align with the first key, which sits one space after the hyphen:
containers:
- name: api # 'name' starts at column 5
image: api:2.4.1 # 'image' must start at column 5 too
ports:
- containerPort: 8080
Putting image at column 7 to line it up under name's value
is the single most common YAML mistake. It produces a bad-indentation error.
Depth as a warning sign
Past about five levels, indentation stops helping. The content is pushed so far right that a reviewer cannot see which branch a line belongs to, and adding a level means re-indenting everything below it.
Deep files are also where the YAML validator earns its keep: reading the parsed output is far quicker than counting spaces by eye.
When a file gets that deep, the structure is usually the problem rather than the format. Split it into multiple files, flatten a level with dotted keys, or use anchors to lift repeated blocks to the top.