YAML Basics

Page 05 — What YAML is, why indentation matters, and common patterns. Read before Ansible.

What YAML is

YAML is a human-readable data format. It is used heavily in automation tools like Ansible to store:

The most important rule

Indentation matters. Bad indentation breaks structure. YAML uses spaces (never tabs) to define hierarchy. Two spaces per level is the most common convention.

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"
Tip: Quote strings that contain special characters like :, #, *, 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

Never use tabs. YAML parsers reject them. Configure your editor to expand tabs to 2 spaces automatically.

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:

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.

Tip: Always start your Ansible playbooks and variable files with ---. 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.

Ansible note: Ansible's YAML parser supports anchors in variable files and playbooks. They are evaluated at parse time, before any Jinja2 templating. Use them to reduce copy-paste in 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").

Lint your YAML: yamllint . catches indentation errors, trailing spaces, and truthy string warnings before they hit CI. Install with pip install yamllint or dnf install yamllint.