YAML Basics
What YAML is
YAML is a human-readable data format. It is used heavily in automation tools like Ansible to store:
- Settings and configuration
- Variables and defaults
- Structured data like inventories and playbooks
The most important rule
Dictionary (key-value pairs)
Keys and values at the same indentation level form a dictionary:
name: nginx
state: started
enabled: true
Lists
Each list item starts with - and is indented under its key:
packages:
- nginx
- git
- curl
Nested values
A key can contain a nested dictionary by indenting further:
service:
name: nginx
state: started
enabled: true
List of dictionaries
Each list item can itself be a dictionary. This pattern is very common in Ansible:
users:
- name: alice
shell: /bin/bash
- name: bob
shell: /bin/zsh
Strings
simple: hello
quoted: "hello world"
path: "/etc/nginx/nginx.conf"
:, #, *, or that start with {. When in doubt, quote it.
Booleans
Always use lowercase true and false:
enabled: true
disabled: false
Avoid yes/no, True/False, or on/off — different YAML parsers handle these differently.
Null
value: null
Common mistakes
Bad indentation
# Wrong — items at inconsistent levels
packages:
- nginx
- git
# Correct — all items at the same indent under key
packages:
- nginx
- git
Tabs instead of spaces
Missing colon
# Wrong
name nginx
# Correct
name: nginx
Mixing indentation levels
All items in the same list or dictionary must be at exactly the same indent depth. Mixing levels causes parse errors.
Why YAML matters for Ansible
If you are using Ansible, you will be reading and writing YAML constantly:
- Playbooks
- Inventories
- Variable files
- Role defaults
- Task files
Getting comfortable with YAML structure is a big unlock before starting Ansible work.
Document start (---)
Three dashes --- mark the start of a YAML document. In a single file you can have multiple documents separated by ---.
---
- name: First play
hosts: all
tasks: []
Ansible playbooks conventionally begin with ---. It is optional for a single document, but including it is a good habit because it signals clearly "this file is YAML" and satisfies most YAML linters.
---. It costs nothing and avoids confusion.
Multiline strings
Two styles exist for writing multi-line text values.
Literal block (|) — preserves newlines
message: |
Line one.
Line two.
Line three.
The value is exactly what you see, newlines and all. Use this for scripts, file content, or any text where line breaks matter.
Folded block (>) — newlines become spaces
description: >
This is a long sentence that
wraps across several lines for
readability in the file.
The value is treated as a single paragraph — newlines become spaces. Use this when you want to wrap long strings in the file without introducing actual line breaks in the value.
Anchors and aliases
YAML anchors let you define a value once and reuse it, reducing repetition. This is heavily used in GitLab CI/CD pipelines and complex Ansible variable files.
# Define a reusable block with & (anchor)
defaults: &defaults
image: python:3.11
before_script:
- pip install -r requirements.txt
# Reuse it with * (alias)
test:
<<: *defaults # merge the anchor block into this mapping
script:
- pytest
deploy:
<<: *defaults # same base, different script
script:
- ansible-playbook site.yml
&name declares an anchor. *name references it. <<: is the merge key — it merges all key/value pairs from the aliased mapping into the current mapping. Keys defined locally override merged ones.
group_vars or large defaults/main.yml files.
Chomping (|- >-)
Block scalars (| and >) have a chomping indicator that controls the trailing newline behaviour.
# | preserves newlines; trailing newline included by default
script: |
echo "line one"
echo "line two"
# value ends with one newline
# |- strips the trailing newline
script: |-
echo "line one"
echo "line two"
# value ends with "line two" — no newline at all
# |+ keeps ALL trailing newlines (rarely useful)
script: |+
echo "line one"
# Same chomping works on folded blocks
description: >-
This sentence wraps but
has no trailing newline.
The most common trap: using | when you wanted |-, which adds a phantom blank line at the end of a shell script or template value. When in doubt, use |- for command blocks and | for file content that should end with a newline.
Explicit types
YAML 1.1 (used by many parsers) has a broad set of truthy/falsy strings. This bites Ansible users constantly.
# These are all parsed as boolean true in YAML 1.1:
val1: yes
val2: on
val3: true
val4: True
# Force a string type with !! prefix
val5: !!str "yes" # string "yes", not boolean
val6: !!str "on" # string "on"
# Force numeric
port: !!int "8080" # safe when the value might be quoted elsewhere
Ansible itself wraps values in quotes where ambiguity exists, but third-party tools, Helm values, and raw YAML parsers can all surprise you. The safe rule: always quote strings that look like booleans, numbers, or null ("yes", "true", "null", "1.0").
yamllint . catches indentation errors, trailing spaces, and truthy string warnings before they hit CI.
Install with pip install yamllint or dnf install yamllint.