YAML for Configuration: A Practical Guide
Published February 8, 2026
Why YAML Dominates Configuration
Every modern infrastructure tool uses YAML: Kubernetes, Docker Compose, Ansible, GitHub Actions, GitLab CI, Terraform variable files, Helm charts. Why? Because YAML prioritizes human readability over parser simplicity — it drops JSON's braces, brackets, and mandatory quoting in favor of indentation and bare words.
That readability comes at a cost: YAML's spec (over 80 pages, versus a one-page JSON grammar) hides genuine gotchas that silently corrupt config files. This guide covers the syntax you need day-to-day, and the specific traps that catch experienced engineers.
YAML Syntax Essentials
YAML uses indentation to define hierarchy — two spaces per level is the near-universal convention, and tabs are outright forbidden by the spec (most parsers throw a hard error). A mapping (object) and a sequence (array) look like this:
The same structure as JSON: service is an object with scalar fields (name, port), a sequence (tags), and a nested object (healthcheck) — just without the punctuation.
Block Scalars: Multi-Line Strings
Configuration files often need to embed multi-line text — a shell script, a SQL query, a certificate. YAML has two block scalar styles that behave very differently:
Literal Block (|) — preserves newlines
Folded Block (>) — folds newlines to spaces
Mixing these up is a common source of broken shell scripts embedded in CI YAML: a folded block (>) will silently collapse your multi-line script into one space-joined line, which usually still "parses" but runs the wrong command.
Anchors and Aliases: Keeping Config DRY
YAML lets you define a block once with an anchor (&name) and reuse it with an alias (*name) — this is how CI pipelines share environment config across jobs without copy-pasting:
The << merge key applies everything from *defaults, then lets each environment override or add keys. Both development and test end up with adapter and timeout without repeating them.
The Gotchas That Break Real Config Files
✗ The "Norway Problem" — implicit typing
Unquoted NO, YES, ON, OFF, TRUE, and FALSE are all parsed as booleans by YAML 1.1 parsers (used by most real-world tools). This is infamous for turning a country code into a boolean:
Fix: always quote ambiguous scalars — country: "NO".
✗ Version numbers become floats
version: 1.10 is parsed as the number 1.1, silently dropping the trailing zero. If a version string needs to preserve exact formatting, quote it: version: "1.10".
✗ Tabs are illegal for indentation
Unlike most languages, YAML's spec forbids tabs for indentation entirely — a single stray tab character (often pasted in from another file) throws a hard parse error rather than a warning. Configure your editor to insert spaces for YAML files specifically.
✗ Unsafe deserialization (security)
Some YAML libraries (notably older PyYAML defaults) support tags that instantiate arbitrary language objects from the document itself — loading untrusted YAML with a non-safe loader can lead to code execution. Always use the "safe load" function of your language's YAML library (e.g. yaml.safe_load() in Python) when parsing YAML from an external or user-supplied source.
✗ Trailing whitespace changes meaning
A trailing space after a key's colon, or inconsistent indentation by a single column, can silently nest a key under the wrong parent instead of failing outright — because YAML's indentation rules are structural, not just cosmetic like in most languages.
Multi-Document Files
A single YAML file can contain multiple documents separated by ---. Kubernetes uses this constantly to define several resources (a Deployment and a Service, say) in one manifest:
Best Practices for Configuration
1. Consistent Indentation (2 spaces)
Define it in .editorconfig and enforce it in CI with yamllint so a misaligned commit fails the build instead of production.
2. Quote Ambiguous String Values
Quote anything that looks like a boolean, number, null, or date but is meant to be a string — country codes, version strings, ports read as env-var placeholders.
3. Use Anchors for DRY Config
Don't repeat configuration blocks across environments or CI jobs — use anchors and merge keys (& / * / <<) instead.
4. Add Comments Liberally
YAML supports # comments where JSON has none — use them to explain why a value is set, not just what it is.
5. Validate Against a Schema
Use tool-specific schema validation (Kubernetes' kubeconform, a JSON Schema for custom configs) before deploying, since YAML's own type system won't catch a misspelled key.
6. Use Environment-Specific Overrides
Define a base config and override only what changes per environment (prod/staging/dev), rather than maintaining three full copies that drift apart.
Converting and Validating YAML
If you need to move data between YAML and JSON — for example, exporting a Kubernetes ConfigMap as JSON for a script, or converting a JSON API response into a YAML config file — use SmartJson's YAML formatter and validator to catch indentation and type errors like the ones above before they reach production, entirely in your browser with nothing uploaded to a server.
Key Takeaways
- YAML prioritizes human readability over strict syntax, at the cost of a much larger spec than JSON
- Indentation is structural — two spaces per level is standard, and tabs are a hard parse error
- Literal blocks (
|) preserve newlines; folded blocks (>) collapse them to spaces — don't mix them up in scripts - Quote any scalar that could be misread as a boolean, number, or null (the "Norway problem")
- Use anchors (
&) and aliases (*) to keep multi-environment config DRY - Always use your language's "safe load" function when parsing YAML from an untrusted source
- Validate config against tool schemas before deployment — YAML's parser won't catch a misspelled key