Ansible Lesson 11 – YAML Basics for Ansible | Dataplexa
Section II · Lesson 11

YAML Basics for Ansible

In this lesson

YAML syntax fundamentals Scalars, lists & mappings Indentation rules Multi-line strings Common YAML mistakes

YAML (YAML Ain't Markup Language) is a human-readable data serialisation format that Ansible uses for every playbook, variable file, and inventory. It was designed to be easy to read and write by humans while remaining unambiguous enough for machines to parse. Every Ansible playbook you will ever write is a YAML file — understanding YAML's rules, quirks, and gotchas is therefore not optional. The good news is that YAML is small: once you understand five core concepts, you can read and write any Ansible playbook confidently.

The Five Core YAML Concepts

YAML has a rich specification, but Ansible only uses a small, consistent subset of it. Master these five concepts and you will be able to read and write any playbook in this course.

Concept 1

Documents start with ---

Every YAML file begins with three dashes on the first line. This marks the start of the document. Ansible requires it for playbooks and recommends it for all YAML files.

Concept 2

Indentation defines structure

YAML uses spaces — never tabs — to show hierarchy. Child items are indented further than their parent. Ansible convention is 2 spaces per level.

Concept 3

Key-value pairs are mappings

The fundamental data structure: key: value. The colon must be followed by a space. Values can be strings, numbers, booleans, lists, or other mappings.

Concept 4

Lists use a dash prefix

Each item in a list is prefixed with - (dash space). Lists can contain scalars, mappings, or other lists. In Ansible, the list of tasks in a play is written this way.

Concept 5

Comments start with #

Anything after a # on a line is ignored by the parser. Use comments liberally in playbooks to explain why a task exists, not just what it does. Good comments are the cheapest documentation you will ever write.

The Outline Analogy

YAML is like a perfectly formatted outline. Top-level items are flush left. Sub-items are indented beneath their parent. Sub-sub-items are indented further still. The indentation is the structure — there are no curly braces, no angle brackets, no semicolons. If your outline looks right visually, it will parse correctly. If the indentation is off by even one space, the structure breaks — just like an outline where a heading is accidentally indented under the wrong parent.

Scalars, Lists, and Mappings

YAML has three fundamental data types. Every value in a playbook is one of these three, and they nest freely inside each other to build complex structures.

Scalars — single values

---
# Strings — quotes are optional unless the string contains special characters
name: "Ansible automation"
simple_string: hello world       # no quotes needed here

# Integers and floats
port: 8080
timeout: 30.5

# Booleans — YAML accepts several forms; Ansible convention is true/false (lowercase)
enabled: true
debug_mode: false

# Null value
optional_param: null             # or leave the value blank: optional_param:

Lists — ordered sequences

---
# Block style — each item on its own line with a dash
packages:
  - nginx
  - git
  - curl
  - python3

# Inline (flow) style — compact, useful for short lists
ports: [80, 443, 8080]

# List of mappings — the pattern used for Ansible task lists
tasks:
  - name: Install Nginx           # first task (a mapping inside a list)
    ansible.builtin.package:
      name: nginx
      state: present

  - name: Start Nginx             # second task
    ansible.builtin.service:
      name: nginx
      state: started

Mappings — key-value pairs (dictionaries)

---
# Simple mapping
app:
  name: myapp
  version: "2.1.0"
  port: 3000

# Nested mappings — hierarchy is expressed through indentation
server:
  hardware:
    cpu: 4
    memory_gb: 16
  network:
    interface: eth0
    ip: 192.168.1.10

# Inline (flow) style mapping — compact, for simple cases
coordinates: {x: 10, y: 20}

Indentation Rules

Indentation is the single most common source of YAML errors in Ansible. The rules are simple but unforgiving — a single misplaced space produces a parse error or, worse, silently changes the structure of your playbook. Understanding these rules eliminates 80% of YAML debugging time.

- name: Configure web server hosts: webservers tasks: - name: Install Nginx ansible.builtin.package: name: nginx state: present 0 spaces — play level 2 spaces — play attributes 4 spaces — task list item 6 spaces — module name 8 spaces — module arguments

Indentation rules — all non-negotiable

1
Use spaces only — never tabs. YAML explicitly forbids tab characters for indentation. Most editors can be configured to insert spaces when you press Tab. VS Code does this automatically for YAML files.
2
Use 2 spaces per indentation level. Ansible's style guide mandates 2 spaces. Consistent indentation across a project is more important than the specific number — but 2 spaces is the convention.
3
Module arguments must be indented under the module name. When a module has parameters, they must be one indentation level deeper than the module name line itself.
4
All items in a list must be at the same indentation level. If one list item is at 4 spaces and another at 6 spaces, they are not in the same list — this is a bug, not a style choice.

Strings and Quoting

YAML's string handling is one of its most misunderstood features. Most strings do not need quotes — but a small set of situations require them. Knowing when to quote prevents subtle parsing bugs that are very hard to diagnose.

---
# No quotes needed — plain string values
description: Deploy application to production
hostname: web01.example.com

# MUST quote — starts with a special character
colon_value: "key: value"        # colon in value requires quotes
hash_value: "#not-a-comment"     # # would start a comment without quotes
curly_value: "{{ variable }}"    # Jinja2 expressions ALWAYS need quotes in Ansible

# MUST quote — YAML would interpret these as non-string types without quotes
version: "1.0"                   # without quotes: parsed as float 1.0
enabled_str: "true"              # without quotes: parsed as boolean true
port_str: "8080"                 # without quotes: parsed as integer 8080

# Single vs double quotes
# Single quotes: literal — no escape sequences, no variable interpolation
path: '/etc/nginx/conf.d'
# Double quotes: allows escape sequences (\n, \t) and Jinja2 interpolation
message: "Hello, {{ user_name }}\n"

Multi-line Strings

Ansible frequently needs multi-line string values — shell scripts, configuration blocks, certificate content. YAML provides two dedicated operators for this: | (literal block) and > (folded block). Understanding the difference is important because they behave very differently when the string is consumed by a shell command.

---
# Literal block ( | ) — preserves newlines exactly as written
# Use for shell scripts, config file content, anything where line breaks matter
script: |
  #!/bin/bash
  echo "Starting deployment"
  cd /var/www/app
  git pull origin main
  systemctl restart app

# Folded block ( > ) — newlines become spaces (text is re-wrapped)
# Use for long prose descriptions where line breaks are just for readability
description: >
  This playbook deploys the application
  to all web servers in the production group,
  restarts the service, and runs a health check.
# Result: "This playbook deploys the application to all web servers..."

# Literal block with chomping modifiers:
# |-  strips the trailing newline (most common in Ansible)
# |+  keeps all trailing newlines
inline_script: |-
  echo "no trailing newline after this"

Common YAML Mistakes in Ansible

These are the mistakes that show up most frequently in pull request reviews and failed playbook runs. Each one produces a specific, identifiable error — learning to recognise them means you spend seconds fixing them instead of minutes debugging.

Mistake 1 — Missing space after colon

❌ Wrong

name:nginx
state:present

✓ Correct

name: nginx
state: present
Mistake 2 — Jinja2 expression without quotes

❌ Wrong — YAML parse error

name: {{ app_name }}
dest: {{ deploy_path }}/app

✓ Correct — always quote Jinja2

name: "{{ app_name }}"
dest: "{{ deploy_path }}/app"
Mistake 3 — Tab characters instead of spaces

❌ Wrong — tabs cause parse errors

tasks:
	- name: Install Nginx  # ← tab!

✓ Correct — 2 spaces

tasks:
  - name: Install Nginx  # ← spaces
Mistake 4 — Unquoted yes/no parsed as boolean

❌ Wrong — yes/no become true/false

answer: yes
response: no

✓ Correct — use true/false or quote

enabled: true
answer: "yes"   # if you need the string "yes"

Catch YAML errors instantly: Install yamllint and run it against every playbook before committing. It catches all four mistakes above in under a second.

yamllint docs ↗

Always Quote Jinja2 Expressions — No Exceptions

A Jinja2 expression that starts a YAML value — {{ variable }} — must always be wrapped in double quotes. Without quotes, YAML's parser sees the opening { and attempts to parse a flow mapping, producing a cryptic error: "mapping values are not allowed here". This is one of the most common Ansible errors beginners hit, and the fix is always the same: add double quotes around the entire value.

Key Takeaways

YAML uses indentation to define structure — 2 spaces per level, spaces only, never tabs. A single misplaced space changes the entire meaning of a value.
The three data types are scalars, lists, and mappings — they nest freely inside each other. An Ansible task list is a list of mappings, and module parameters are nested mappings inside each task.
Always quote Jinja2 expressions — any value starting with {{ must be wrapped in double quotes or Ansible will throw a YAML parse error.
Use | for literal multi-line strings — when newlines must be preserved (shell scripts, config blocks). Use > when newlines are just for readability and should be collapsed to spaces.
Run yamllint on every file before committing — it catches tabs, missing spaces after colons, indentation errors, and boolean confusion instantly and automatically.

Teacher's Note

Open VS Code, create a new .yml file, and type out each example in this lesson by hand — not copy-paste. The muscle memory of correct indentation is worth more than any amount of reading.

Practice Questions

1. What three characters must appear on the first line of every YAML document to mark its start?



2. Which YAML multi-line string operator preserves newlines exactly as written — making it suitable for shell scripts?



3. A Jinja2 expression like {{ app_name }} used as a YAML value must always be wrapped in what?



Quiz

1. Your playbook fails to parse with the error "found character '\\t' that cannot start any token". What is the cause?


2. A variable is defined as restart_service: true in a variable file. What type does YAML assign to this value?


3. In an Ansible playbook, the tasks: block contains a series of task definitions each starting with - name:. What YAML data structure is this?


Up Next · Lesson 12

Playbooks Introduction

With YAML under your belt, it is time to meet the playbook — Ansible's core automation document. Learn its structure, anatomy, and how plays, tasks, and hosts fit together.