Ansible Course
YAML Basics for Ansible
In this lesson
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.
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.
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.
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.
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.
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.
Indentation rules — all non-negotiable
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.
❌ Wrong
name:nginx state:present
✓ Correct
name: nginx state: present
❌ Wrong — YAML parse error
name: {{ app_name }}
dest: {{ deploy_path }}/app
✓ Correct — always quote Jinja2
name: "{{ app_name }}"
dest: "{{ deploy_path }}/app"
❌ Wrong — tabs cause parse errors
tasks: - name: Install Nginx # ← tab!
✓ Correct — 2 spaces
tasks: - name: Install Nginx # ← spaces
❌ 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.
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
{{ must be wrapped in double quotes or Ansible will throw a
YAML parse error.
| 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.
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.