python
jinja
template
loop.counter
web-development

How to output loop.counter in python jinja template?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Jinja templates, the value people often look for as loop.counter is actually exposed under a different name. Jinja uses loop.index for a one-based counter and loop.index0 for a zero-based counter, so the fix is mostly about using the correct loop variable.

Use loop.index Instead of loop.counter

Inside a Jinja for loop, loop.index gives you the current iteration number starting from 1.

jinja
1<ul>
2{% for name in names %}
3  <li>{{ loop.index }}. {{ name }}</li>
4{% endfor %}
5</ul>

If names is ["Ana", "Bob", "Cara"], the rendered output becomes:

html
1<ul>
2  <li>1. Ana</li>
3  <li>2. Bob</li>
4  <li>3. Cara</li>
5</ul>

That is the direct Jinja equivalent of the loop counter many developers expect from other template engines.

Use loop.index0 for Zero-Based Counting

If you need a counter that starts at 0, use loop.index0.

jinja
{% for value in values %}
  <p>index={{ loop.index0 }}, value={{ value }}</p>
{% endfor %}

This is useful when the template output has to match zero-based array indexes or JavaScript code.

Jinja also provides other loop helpers:

  • 'loop.first'
  • 'loop.last'
  • 'loop.revindex'
  • 'loop.revindex0'
  • 'loop.length'

Those are often more expressive than manually calculating conditions from the counter.

Full Example with Flask

Here is a minimal Flask app that passes data to a template and renders the loop index correctly.

python
1from flask import Flask, render_template_string
2
3app = Flask(__name__)
4
5TEMPLATE = """
6<table>
7{% for student in students %}
8  <tr>
9    <td>{{ loop.index }}</td>
10    <td>{{ student }}</td>
11  </tr>
12{% endfor %}
13</table>
14"""
15
16@app.route("/")
17def index():
18    students = ["Ana", "Bob", "Cara"]
19    return render_template_string(TEMPLATE, students=students)
20
21if __name__ == "__main__":
22    app.run(debug=True)

When you open the page, the first column contains 1, 2, and 3.

Nested Loops Need Care

In nested loops, loop always refers to the current loop. If you need the outer loop later, save it to another template variable before entering the inner loop.

jinja
1{% for row in rows %}
2  {% set outer_loop = loop %}
3  {% for item in row %}
4    <p>row {{ outer_loop.index }}, col {{ loop.index }}: {{ item }}</p>
5  {% endfor %}
6{% endfor %}

Without that extra assignment, the inner loop would overwrite your reference to the outer one.

Avoid Computing Counters in Python When Jinja Already Has Them

Sometimes people pre-enumerate data in Python just to get a display counter:

python
items = list(enumerate(["Ana", "Bob", "Cara"], start=1))

That works, but it is often unnecessary when the template is already looping over the items. Using Jinja's built-in loop metadata keeps the view code simpler:

jinja
{% for item in items %}
  {{ loop.index }} - {{ item }}
{% endfor %}

Let the template handle presentation counters unless the index itself is part of the business data.

Common Pitfalls

The biggest mistake is assuming Jinja has a loop.counter variable because another template engine uses that name. Another common issue is confusing loop.index with loop.index0, which causes off-by-one numbering in the rendered output. Developers also run into trouble with nested loops when they expect loop to keep pointing at the outer iteration. Finally, some code enumerates data in Python and then also uses loop.index in the template, which creates redundant counters and harder-to-read templates.

Summary

  • Jinja does not use loop.counter; use loop.index for one-based counting.
  • Use loop.index0 when you need zero-based counting.
  • Jinja loop objects also expose helpers such as loop.first and loop.last.
  • Save the outer loop to another variable if you need it inside nested loops.
  • Prefer Jinja's built-in loop metadata over extra counter preparation in Python when possible.

Course illustration
Course illustration