Jinja2 Templating
Ansible uses a templating engine called Jinja2 to let you drop a variable’s value into a string — that {{ }} syntax you’ll see constantly from here on. Jinja2 itself is a much bigger templating language than we need right now; this chapter covers just enough of it to use variables comfortably. Special placeholders in the template also allow writing code similar to Python syntax which is left for readers to explore.
Printing A Variable With {{ }}
{{ variable_name }} substitutes that variable’s current value into wherever it appears. We haven’t properly covered how to define variables yet — that’s the next chapter — so for now, here’s just enough to see the substitution happen:
- name: Jinja2 Basics
hosts: servers
vars:
greeting: "Hello from Jinja2"
tasks:
- name: Print the variable
ansible.builtin.debug:
msg: "{{ greeting }}"TASK [Print the variable] *******************************************
ok: [ubuntu] => {
"msg": "Hello from Jinja2"
}
ok: [fedora] => {
"msg": "Hello from Jinja2"
}{{ greeting }} was replaced with the variable’s actual value before debug ever saw the string.
A Few Filters Worth Knowing Now
A filter transforms a value on its way through {{ }}, using a pipe (|) — the same idea as a shell pipeline, applied to a single value instead of a stream of text.
default
Falls back to a given value if the variable is undefined:
msg: "{{ nickname | default('friend') }}"If nickname was never set, this prints friend instead of failing outright. This is worth reaching for defensively any time a variable might genuinely not be set — undefined-variable errors are one of the most common ways a playbook fails partway through.
upper / lower
msg: "{{ greeting | upper }}"HELLO FROM JINJA2Straightforward case conversion, applied to whatever the variable holds.
join
Combines a list into a single string with a separator:
vars:
fruits: [apple, banana, cherry]
tasks:
- name: Print the list as a sentence
ansible.builtin.debug:
msg: "{{ fruits | join(', ') }}"apple, banana, cherryWhere {{ }} Is (And Isn’t) Valid
{{ }} works inside a YAML string value — not as a key, and not always safely as an entire unquoted value on its own. Watch this specific case:
msg: {{ greeting }}Written exactly like that, without quotes, this can trip up the YAML parser — YAML treats a leading { as the start of its own flow-style mapping syntax, and gets confused before Jinja2 ever gets a chance to run. The fix is simple and worth making a habit: quote any value that starts with a Jinja2 expression.
msg: "{{ greeting }}"Best Practices
- Quote a value whenever
{{ }}appears at the very start of it — sidesteps a YAML-parsing gotcha that has nothing to do with Jinja2 itself. - Use
| default(...)defensively for any variable that isn’t guaranteed to be set, rather than letting a playbook fail on an undefined variable partway through a run. - Keep templating simple for now. This chapter is deliberately just enough to read and write a basic expression — loops, conditionals, and custom filters inside Jinja2 are real, deeper features, not needed for anything in this course yet.