Ansible Jinja Templates Explained with Real world examples
Here I'm starting this post with famous ARISTOTLE quote.
"We are what we repeatedly do. Excellence, then is not an act, but a Habit"
Welcome back Ansible Automations and who are habituated as Ansible automation specialists this post for them to give boosted walk through, In this post why Jinja templates, When managing hundreds of Linux servers, it becomes difficult to maintain separate configuration files for each environment. Development, Testing, UAT, and Production environments often require different values such as hostnames, IP addresses, ports, memory settings, and application URLs.
- What is Jinja2 template do in Ansible?
- Template with filters
- Template with Lists and sets
- Template module in Ansible
- Template with Flow Control
- Template using Looping
- Template inheritance**
What is Jinja2 template do in Ansible?
| Let's explore more about Ansible Jinja templates experiments with examples. |
Real World Use case
| Environment | Server | Port |
|---|---|---|
| Development | dev-app01 | 8080 |
| Testing | test-app01 | 8081 |
| Production | prod-app01 | 80 |
server_name={{ inventory_hostname }}
application_port={{ app_port }}
The Generated output on Production environment:
server_name=prod-app01 application_port=80Similarly, Generated output on Development:
server_name=dev-app01 application_port=8080This is the power of templating in Ansible.
Prerequisites Core Ansible to work with Jinja templates
apt install python3.12-venv #Allow python3 to create virtual environment python3 -m venv venv source venv/bin/activate python3 -m pip install ansible-core==2.18.5 # As of 16th May 2025 ansible --version
How to use string filters in a playbook?
---
- name: test string values
hosts: localhost
vars:
my_name: 'Pavan Deverakonda the great'
tasks:
- name: String filter examples
debug:
msg:
- "The name is {{ my_name }}"
- "The name is {{ my_name |upper }}"
- "The name is {{ my_name |lower }}"
- "The name is {{ my_name |title }}"
- "The name is {{ my_name |replace('Pavan','Raghav') }}"
- "The name is {{ title |default('Mr.') }}{{ my_name }}"
| Applying string filters on text in a Ansible playbook |
How to play with Jinja2 lists and sets in Ansible?
It is very simple to understand about the Lists and Sets in Jinja2 they can be operated similar to Python Lists and Sets here in the Ansible we need to use them in the YAML as follows:
---
- name: test aggregate values
hosts: localhost
vars:
mylist: [10,20,30]
x: [8,3,9,5,1]
y: [44, 5,5]
words: ["Learning","by","doing"]
tasks:
- name: aggregate filter examples
debug:
msg:
- "The max {{ mylist|max }}"
- "The min {{ mylist|min }}"
- "The last {{ mylist|last}}"
- name: set filters
debug:
msg:
- "The unique: {{ [2,5,2,9,7,5]|unique }}"
- "The union: {{ x|union(y) }}"
- "The another union: {{ [10,3.4]|union([4,2])}}"
- "The intersect: {{ x|intersect(y) }}"
- "The intersect: {{ [10,20,30,10]| intersect ([40,30])}}"
- "The joining words: {{ words|join(' ') }}"
The execution on the lists and sets goes here as output:
| Jinja2 Lists and Sets in Ansible playbooks |
How to write an Ansible playbook using templates?
It's so simple to use the Jinja2 templates in the Ansible playbooks. To know all the available default ansible variables at the runtime, you can inspect with the following command:ansible -m setup localhostIt will give you the facts about the localhost. To filtering out to get all the facts which starts with 'ansible_'
ansible -m setup db |grep ansible_
| ansible_user details using ansible command setup module |
Writing Simple Ansible playbook using templates module
Ansible uses Jinja2 templates where it can be lookup inside 'templates' folder, where your playbook runs. All the values of variables will replaced at the time of running the playbook. Runtime value replaces at the time of remote execution.cat templates/sample-conf.j2
env = {{ env }}
remote_ip = {{ ansible_host }}
remote_user = {{ ansible_user_id}}
remote_hostname = {{ (ansible_fqdn|default(ansible_host)) }}
To test the template values in the playbook write it as :
# File: mytemplate-test.yaml
---
- name: test template values
hosts: web
vars:
env: dev
tasks:
- name: template module runs on remote
template:
src: sample-conf.j2
dest: /etc/sample.conf
become: true
Advanced settings for templates
adding the user, group, file permissions with mode attributes.
ansible-playbook mytemplate-test.yaml -b
setup the permissions on the templated files.
| Ansible Jinja template experiment |
Now connect to the Node1 or Node2 where this hosts are in the play, and check that file content of /etc/sample.conf
| Jinja2 template execution with ansible playbook |
How to specify "if else" statements in Ansible Jinja2 (.j2) templates?
- debug:
msg: "{% if test_var == true %} Good to go!{% else %} Not operational!{% endif %}"
You can also include the ansible facts in the message content.
controlplane $ cat condition1.yml
- name: Condition test
hosts: localhost
gather_facts: no
vars:
test_var: yes
tasks:
- name: checking if-condition
debug:
msg: "{% if test_var == true %} Good to go!{% else %} Not operational!{% endif %}"
| Simple if-else Jinja template syntax in Ansible playbook |
Looping with Jinja templates
Here is a fun looping playbook which will be using a list variable 'myex' that stored all my experiances in the IT industry.---
- name: Testing Jinja templates with loops
hosts: localhost
vars:
myex: ['Teleparadigm','IBM Global Services','BirlaSoft','Virtusa','Rubicon Red', 'Oracle Corporation','Garmin']
tasks:
- name: extracting my experiance
template:
src: myex.j2
dest: /tmp/experiance.txt
Jinja template you can store in a file called myex.j2
This is my experience list:
{% for e in myex %}
{{loop.index}}. {{ e }}
{% endfor %}
When we run the playbook we could see a nice output as:| Loops in Jinja templates in Ansible playbook |
Nested loops in Jinja template
ansible-galaxy init jinja-templates
tree jinja-templates/
jinja-templates/
|-- README.md
|-- defaults
| `-- main.yml
|-- files
|-- handlers
| `-- main.yml
|-- meta
| `-- main.yml
|-- tasks
| `-- main.yml
|-- templates
|-- tests
| |-- inventory
| `-- test.yml
`-- vars
`-- main.yml
- Create variables which will contain a map/dictionary
- Define a task that uses template module and generates output
- Create template that will referring to the variables defined in the step 1
- Add a configuration to work with the do statement in template
- Create main playbook to test the nested loop in Jinja Template
---
inspiring_people:
- name: Nielgogte
fav_colour: Blue
- name: Siva
fav_colour: Blue
- name: RanjanShee
fav_colour: Orange
- name: Sanjeet
fav_colour: Orange
- name: Pankaj
fav_colour: Yellow
- name: Prateek
fav_colour: Blue
colours:
- name: Blue
thinks:
- Sky is The Limit
- See as sea into the Depth
- name: Yellow
thinks:
- Expressive
- Task Oriented
- Brainstroming
- name: Orange
thinks:
- Proactive
- Extreme
- Cares a lot
- name: Create the Jinja2 based template template: src: inspiring.j2 dest: /tmp/impactingMe.out
- Some variable names modified to test how they are working
- Inside the template I've used Jinja filter ' | upper'.
---
{% for colour in colours %}
Colour number {{ loop.index }} is {{ colour.name }}.
{% set colour_count = 0 %}
{% for person in inspiring_people if person.fav_colour == colour.name %}
{{ person.name | upper }}
{% set colour_count = colour_count + 1 %}
{% do colour.update({'inspiring_people_count':colour_count}) %}
{% endfor %}
Currently {{ colour.inspiring_people_count }} inspiring_people choose color {{ colour.name }} as their favourite.
And the following are their thoughts for {{ colour.name }} :
{% for item in colour.thinks %}
-> {{ item }}
{% endfor %}
{% endfor %}
All set to test our new learning that is nested loop within Jinja2 templates in Ansible---
- name: Demonstrating variables in Jinja2 Loops
hosts: localhost
connection: local
gather_facts: no
roles:
- jinja-templates
tasks:
- name: display file
shell: cat /tmp/impactingMe.out
register: output
- debug:
msg: "{{ output.stdout.split('\n') }}"
| Ansible nested loops in Jinja Templates |
Template Inheritance
---
- name: Create index.html page
hosts: localhost
gather_facts: false
vars:
title: My Ansible experiment Website
description: A sample website created with Ansible and Jinja2 templates
keywords: sample, website, Ansible, Jinja2
tasks:
- name: Create head template
template:
src: templates/head.j2
dest: head.html
- name: Create body template
template:
src: templates/body.j2
dest: body.html
- name: Create index.html
template:
src: templates/index.j2
dest: index.html
Finally, here's an example of the index.j2 template, which extends the body.j2 and includes head.html that was generated with `head.j2` templates:
{% include "head.html" %}
{% extends "body.j2" %}
| Creation of web page using Jinja2 templates |
Best Practices Ansible Templates
Keep Templates Simple Avoid embedding complex business logic in templates. Templates should primarily focus on variable substitution and simple conditions. Store Variables Separately Better way of use:group_vars/ host_vars/instead of hardcoding values. Use Meaningful Variable Names Good exmples for Variables that used in Templates must have proper meaning: app_port database_host nginx_server_name Avoid:
a b c x1Validate Generated Files Always test the generated configurations from Jinja before restarting services.
Common Misstakes and Troubleshooting
1. Variable Undefined
'myvariable' is undefinedSolution:
Verify variable spelling and inventory definitions.
2. Incorrect Jinja Syntax
{ variable }
But Correct syntax is double flower brackets:
{{ variable }}
3. Template Not Updating
ansible-playbook site.yml --diffthis command output will show the changes.
Readers Challenge
Try to create the Jinja templates for the following:- Nginx configuration file
- Java application properties
- Kubernetes Deployment Manifest YAML
- HAProxy Load Balancer Configuration
- Multi-environment Terraform variable files
Conclusion
Ansible Jinja2 Templates are a fundamental building block for scalable automation. They allow teams to create dynamic, reusable, and environment-aware configurations without maintaining multiple versions of the same file.
Whether you're managing Application, NGINX, Kubernetes mastering Jinja2 templates will significantly improve your automation capabilities and reduce operational complexity.
Reader Question
What is the most useful configuration file you have automated using Ansible Jinja2 Templates — NGINX, Apache, Kubernetes manifests, Docker Compose, or application properties?

Comments