Skip to content


Jinja2 is a modern and designer-friendly templating language for Python, modelled after Django’s templates. It is fast, widely used and secure with the optional sandboxed template execution environment:

<title>{% block title %}{% endblock %}</title>
{% for user in users %}
  <li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}


  • Sandboxed execution.
  • Powerful automatic HTML escaping system for XSS prevention.
  • Template inheritance.
  • Compiles down to the optimal python code just in time.
  • Optional ahead-of-time template compilation.
  • Easy to debug. Line numbers of exceptions directly point to the correct line in the template.
  • Configurable syntax.


pip install Jinja2


The most basic way to create a template and render it is through Template. This however is not the recommended way to work with it if your templates are not loaded from strings but the file system or another data source:

>>> from jinja2 import Template
>>> template = Template('Hello {{ name }}!')
>>> template.render(name='John Doe')
u'Hello John Doe!'
Jinja uses a central object called the template Environment. Instances of this class are used to store the configuration and global objects, and are used to load templates from the file system or other locations.

The simplest way to configure Jinja to load templates for your application looks roughly like this:

from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])

This will create a template environment with the default settings and a loader that looks up the templates in the templates folder inside the yourapplication python package. Different loaders are available and you can also write your own if you want to load templates from a database or other resources. This also enables autoescaping for HTML and XML files.

To load a template from this environment you just have to call the get_template() method which then returns the loaded Template:

template = env.get_template('mytemplate.html')

To render it with some variables, just call the render() method:

print(template.render(the='variables', go='here'))

Template guidelines


Reference variables using {{ braces }} notation.


One in each line:

{% for host in groups['tag_Function_logdb'] %}
elasticsearch_discovery_zen_ping_unicast_hosts = {{ host }}:9300
{% endfor %}


ALLOWED_HOSTS = [{% for domain in domains %}" {{ domain }}",{% endfor %}]

Get the counter of the iteration

>>> from jinja2 import Template

>>> s = "{% for element in elements %}{{loop.index}} {% endfor %}"
>>> Template(s).render(elements=["a", "b", "c", "d"])
1 2 3 4


Get environmental variable



lineinfile: dest=/etc/hosts line="{{ item.ip }} {{ item.aliases|join(' ') }}"


Get elements of a dictionary

  set_fact: asg_instances="{{ instances.results | map(attribute='instances') | map('first') | map(attribute='public_ip_address') | list}}"


Set default value of variable

name: 'lol'
new_name: "{{ name | default('trol') }}"


Exclude elements from a list.

Filters a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.

If no test is specified, the attribute's value will be evaluated as a boolean.

{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}


{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}
{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}
{{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}

Slice string

{{ variable_name[:-8] }}


Conditional variable definition

{{ 'Update' if files else 'Continue' }}

Check if variable is defined

{% if variable is defined %}
Variable: {{ variable }} defined
{% endif %}

With two statements:

{% if (backend_environment == 'backend' and environment == 'Dev'): %}

{% elif ... %}
{% else %}
{% endif %}

Extract extension from file

s3_object        : code/frontal/
remote_clone_dir : "{{deploy_dir}}/{{ s3_object | basename | splitext | first}}"


{# comment here #}


For simple inclusions use include for more complex extend.


To include a snippet from another file you can use

{% include '_post.html' %}


To inherit from another document you can use the block control statement. Blocks are given a unique name, which derived templates can reference when they provide their content


      {% if title %}
      <title>{{ title }} - Microblog </title>
      {% else %}
      <title>Welcome to Microblog</title>
      {% endif %}
          Microblog: <a href="/index">Home</a>
        {% block content %}{% endblock %}
{% extends "base.html" %}

{% block content %}
{% endblock %}

Execute a function and return the value to a variable

{% with messages = get_flashed_messages() %}
{% if messages %}
  {% for message in messages %}
  <li>{{ message }}</li>
  {% endfor %}
{% endif %}
{% endwith %}


Macros are comparable with functions in regular programming languages. They are useful to put often used idioms into reusable functions to not repeat yourself (“DRY”).

{% macro input(name, value='', type='text', size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{
        value|e }}" size="{{ size }}">
{%- endmacro %}

The macro can then be called like a function in the namespace:

<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>

Wrap long lines and indent

You can prepend the given string with a newline character, then use the wordwrap filter to wrap the text into multiple lines first, and use the replace filter to replace newline characters with newline plus ' ':

{{ ('\n' ~ item.comment) | wordwrap(76) | replace('\n', '\n    ') }}

The above assumes you want each line to be no more than 80 characters. Change 76 to your desired line width minus 4 to leave room for the indentation.

Test if variable is None

Use the none test (not to be confused with Python's None object!):

{% if p is not none %}
    {{ p.User['first_name'] }}
{% else %}
{% endif %}


Last update: 2021-02-26