Jinja2
Templating engine used by Ansible - variable output, filters, conditionals, loops, and practical config templates.
Jinja2 Basics
{{ hostname }}
{{ ansible_default_ipv4.address }}
{{ users | length }}
{# This is a Jinja2 comment - not rendered #}
# /etc/nginx/nginx.conf - managed by Ansible
server {
listen {{ nginx_port | default(80) }};
server_name {{ inventory_hostname }}.{{ domain }};
root {{ document_root | default('/var/www/html') }};
}
PATTERN: Templates live in roles/<name>/templates/ with .j2 extension.
Filters
{{ hostname | upper }} {# WEB-01 #}
{{ hostname | lower }} {# web-01 #}
{{ hostname | capitalize }} {# Web-01 #}
{{ hostname | replace('-', '_') }} {# web_01 #}
{{ " spaced " | trim }} {# spaced #}
{{ path | basename }} {# file.conf #}
{{ path | dirname }} {# /etc/app #}
{{ http_port | default(80) }}
{{ custom_dns | default(omit) }} {# Omit param entirely if undefined #}
{{ optional_list | default([], true) }} {# Default even if defined but empty #}
{{ packages | join(', ') }}
{{ servers | sort }}
{{ servers | unique }}
{{ servers | first }}
{{ servers | last }}
{{ [1, 2, 3] | sum }}
{{ servers | select('match', '^web') | list }}
{{ string_port | int }}
{{ count | string }}
{{ "true" | bool }}
{{ dict_var | to_nice_yaml }}
{{ dict_var | to_nice_json }}
{{ secret | password_hash('sha512') }}
{{ ip_list | ipaddr('address') }}
{{ 'text' | b64encode }}
{{ encoded | b64decode }}
{{ path | regex_replace('^/old', '/new') }}
{{ list_var | regex_findall('pattern') }}
Control Structures
{% if ansible_os_family == 'RedHat' %}
[rhel-base]
name=RHEL Base
baseurl=https://mirror.example.com/rhel/$releasever/
{% elif ansible_os_family == 'Debian' %}
deb https://mirror.example.com/debian/ {{ ansible_distribution_release }} main
{% endif %}
{% for user in users %}
{{ user.name }}:x:{{ user.uid }}:{{ user.gid }}::/home/{{ user.name }}:/bin/bash
{% endfor %}
{% for host in groups['webservers'] %}
server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ http_port }}{% if loop.first %} check{% endif %}
{% endfor %}
{% for item in list %}
{{ loop.index }} {# 1-indexed #}
{{ loop.index0 }} {# 0-indexed #}
{{ loop.first }} {# True on first iteration #}
{{ loop.last }} {# True on last iteration #}
{{ loop.length }} {# Total items #}
{% endfor %}
Practical Templates
# Managed by Ansible - do not edit
backend app_servers
balance roundrobin
{% for host in groups['appservers'] %}
server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port | default(8080) }} check
{% endfor %}
# {{ ansible_managed }}
{% for host in managed_hosts %}
Host {{ host.name }}
HostName {{ host.ip }}
User {{ host.user | default('ansible') }}
IdentityFile {{ ssh_key_path | default('~/.ssh/id_ed25519') }}
{% if host.jump is defined %}
ProxyJump {{ host.jump }}
{% endif %}
{% endfor %}
# {{ ansible_managed }}
[Unit]
Description={{ service_description }}
After=network.target
{% if service_requires is defined %}
Requires={{ service_requires | join(' ') }}
{% endif %}
[Service]
Type={{ service_type | default('simple') }}
User={{ service_user }}
ExecStart={{ service_exec }}
{% for key, value in service_env.items() %}
Environment="{{ key }}={{ value }}"
{% endfor %}
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
PATTERN: Always include # {{ ansible_managed }} at the top of generated configs.
Quick Reference
| Pattern | Description |
|---|---|
|
Output variable value |
|
Conditional block |
|
Loop iteration |
|
Default filter for undefined vars |
|
Join list elements |
|
Convert dict to YAML (Ansible) |
|
Set a variable |
|
Regex substitution (Ansible) |
|
Access inventory group members |
|
Cross-host variable access |