Basics of Jinja Template Language

Jinja Template Language is a small set of constructs which helps us to automate the creation of templates.

Variable, Expression and Function Call

In Jinja double curly {{ }} braces allows us to evaluate an expression, variable or function call and print the result into the template. For example:

Evaluating Expression

Other Python operators like Comparision, Logical and Membership operators are also available inside expressions.

Evaluating Variables

We are not limited to just numbers and strings, Jinja templates can also handle complex data structures like list, dictionary, tuple, and even custom classes.

In case of an invalid index, Jinja will silently output an empty string.

Function call

In Jinja to evaluate a function we simply call it as usual.

Attributes and Method

To access attributes and method of an object use the dot(.) operator.


Jinja has the following syntax to add single or multiline comments inside the templates:

Setting Variables

Inside the template, we can define a variable using the set statement.

We define variables to store the result of some complex operation so that it can be reused across the template. Variables defined outside of control structures (discussed below) act as global variables and can be accessed inside any control structure. However, variables created inside control structure act as local variables and are only visible inside the control structure in which it is defined, the only exception to this rule is the if statement.

Control Structures

Control structures allow us to add control flow and looping inside the templates. By default, control structures use {% ... %} delimiter instead of double curly braces {{ ... }}.

if statement

The if statement in Jinja mimics the if statement in Python and value of the condition determines the flow of the statement. For example:

If the value of variable bookmarks evaluates to true then the string <p>User has some bookmarks</p> will be printed. Remember that in Jinja if a variable is not defined it evaluates to false.

We can also use elif and else clause just like regular Python code. For example:

The control statements can also be nested. For example:

In certain cases, it is quite useful to add if statement in a single line. Jinja supports inline if statement but call it if expression because it is created using double curly braces {{ ... }} instead of {% ... %}. For example:

Here if the variable loggedin evaluates to true then the string “User is logged in” will be printed. Otherwise, the string “User is not logged in” will be printed.

The else clause is optional, if not provided, then the else block will be evaluated to an undefined object.

Here if the loggedin variable evaluates to true then the string “User is logged in” will be printed. Otherwise, nothing will be printed.

Just like Python, we can use Comparision, Logical and Membership operators in control structures to create more complex conditions. Here are some examples:

In case your conditions are becoming too complex or you simply want to alter the operator precedence, you can wrap your expressions inside the parentheses () as follows:

For loop

For loop allows us to iterate over a sequence. For example:


Here is how you can iterate over a dictionary:


Note: In Python elements of a dictionary are not stored in any particular order so the output may differ.

If you want to retrieve key and value of a dictionary at the same time use items() method as follows.


The for loop can also take an optional else clause just like Python, however, its usage is slightly different. Recall that in Python when a for loop is followed by an else clause, the else clause is executed only when for loop terminates after looping over the sequence or when the sequence is empty. It is not executed when the for loop is terminated by the break statement.

When else clause is used with the for loop in Jinja, it is executed only when the sequence is empty or not defined. For example:


Similar to nested if statement, we can also have nested for loop. In fact, we can nest any control structures inside one another.

The for loop gives you access to a special variable called loop to track the progress of the loop. For example:

The loop.index inside the for loop returns the current iteration of the loop starting with 1. The following table lists the other commonly used attributes of the loop variable.

Variable Description
loop.index0 same as loop.index but 0 indexed i.e it starts counting iteration from 0 instead of 1.
loop.revindex returns the iteration from the end of the loop (1 indexed).
loop.revindex0 same as loop.revindex but 0 indexed.
loop.first returns True if the current iteration is the first iteration. Otherwise False.
loop.last returns True if the current iteration is the last iteration. Otherwise False.
loop.length returns the length of the sequence the for loop is iterating over.

Note: For a complete list visit the documentation.


Filters modify the variables before they are rendered. The syntax of using filters is as follows:

Here is an example:

The title filter capitalizes the first character of every word, so if the variable comment is set to "dust in the wind", then the output will be "Dust In The Wind".

We can also chain filters to fine tune the output. For example:

The striptags filter removes all the HTML tags from the variable. In the above code, striptags filter will be applied first followed by the title filter.

Some filters can also accept arguments. To pass arguments to a filter call it like a function. For example:

The round filter rounds the number to the specified number of digits.

The following table lists some commonly used filters.

Name Description
upper converts all the characters to uppercase.
lower converts all the characters to lowercase.
capitalize capitalizes the first character and converts rest of the characters to lowercase.
escape escapes the value
safe prevents escaping
length returns the number of elements in the sequence
trim removes leading and trailing whitespace characters
random returns a random item from the sequence

Note: The complete list of built-in filters is available here.


A Macro in Jinja is similar to a function in Python. The idea is to create reusable code by giving it a name. For example:

Here we have created a macro named render_posts which takes a required argument named post_list and an optional argument named sep. To use a macro call it as follows:

The macro definition must appear before its use otherwise you will get an error.

Rather than sprinkling macros in our templates, it is a good idea to store them in a separate file and then import the file as required.

Let’s say we have stored all our macros in a file named macros.html inside the templates directory. Now to import macros from macros.html we use import statement as follows:

We can now refer to macros defined inside macros.html using the macros variable. For example:

The import statement {% import "macros.html" as macros %} imports all the macros and variables ( defined at the top level) defined inside macros.html into the template. Alternatively, we can also import selected names inside the template using the form statement as follows:

When using macros, you will you encounter cases where you would need to pass an arbitrary number of arguments to a macro.

Similar to *args and **kwargs in Python, inside the macro you have access to varargs and kwargs.

varargs: It captures additional position arguments passed to the macro as a tuple.

kwargs: It captures additional keyword arguments passed to the macro as a dictionary.

Although, you have access to these two variables inside macro you don’t need to explicitly declare them in the macro header. Here is an example:

In this case, additional positional argument i.e "apple" is assigned to varargs and additional keyword arguments ( name='spike', age=15 ) is assigned to kwargs.


By default, Jinja automatically escapes the variable output for security purpose. So if a variable has a string containing HTML like "<p>Escaping in Jinja</p>" then it will be rendered as
"&lt;p&gt;Escaping in Jinja&lt;/p&gt;". This will cause the HTML tags to be displayed in the browser instead of interpreted. In case you know that the data is safe and want to render it as it is without escaping, you can use the safe filter. For example:


Applying safe filter repeatedly to a large block of content can be awkward and inconvenient, that’s why Jinja provides autoescape statement to escape or unescape large blocks of content. It accepts true or false as an argument to turn on and turn off auto-escaping respectively. For example:

Everything between {% autoescape false %} and {% endautoescape %} will be rendered as it is without escaping. If you want to escape some of the elements when auto-escaping is turned off use the escape filter. For example:

Including templates

The include statement renders a template inside another template. The include statement is commonly used to render a static section which is repeated throughout the site. Here is the syntax of the include statement:

Let’s say we have a simple navigation bar stored in nav.html inside templates directory as follows:

To include the navigation bar inside home.html, we use the following code:


Template Inheritance

Template Inheritance is one the most powerful aspects of Jinja Templating. The idea behind template inheritance is somewhat similar to Object Oriented Programming. We start by creating a base template which contains the HTML skeleton and markers that child template can override. The markers are created using the block statement. The child templates uses extends statement to inherit or extends the base templates. Let’s take an example:

This is our base template base.html. It defines three blocks using the block statement where child templates can fill in. The block statement takes a single argument which is the name of the block. Inside the template, the block name must be unique otherwise you will get an error.

A child template is a template which extends the base template. The child template may add, override or leave along the contents of the parent block. Here is how we can create a child template.

The extends statement tells Jinja that child.html is a child template and inherits from base.html. When Jinja encounters the extends statement it loads the base template i.e base.html then replaces the blocks of content in the parent template with the blocks of content of the same name in the child template. In case, a block of matching name isn’t found in the child template then the block from parent template will be used.

Note that in the child template we are only overriding the content block, so the default content from the title and nav will be used while rendering child template. The output should look like this:

If we want, we can change the default the title by overriding the title block in the child.html as follows:

After overriding a block you can still refer to the content in the parent template by calling super() function. The super() call is generally used when child template needs to add its own content in addition to the content from the parent. For example:


That’s all you need to know about Jinja templates. In the upcoming lessons, we will use this knowledge to create some great templates.

2 thoughts on “Basics of Jinja Template Language

  1. Thanks for the tutorial, took me in 5 minutes from zero to he^H^H, hm, a n00b. I needed a quick overview to write a couple of templates, and the official documentation is quite a tome.

    Please check the expression ‘for key in employee.items()’; you probably wanted either ‘for key in employee’, or ‘for key, val in employee.items()’.

  2. Hello,

    Please have a look at below code snippet from base template from .

    {% block head %}

    {% block title %}{% endblock %} – My Webpage
    {% endblock %}

    Can you please let me know why below code can’t work in case of nested blocks in child template?

    {% block head %}

    {% block title %}Hello{% endblock %}
    {% endblock %}

    I am expecting title tag to be included from parent and overidden by title block in child template. Let me know your views on this. I did not find anything on this over internet.

Leave a Comment

%d bloggers like this: