Prompt Templates with Jinja2

Jinja2 is a powerful templating engine that can take your prompts to the next level. See how it’s more powerful than just f-string.

Prompt Templates with Jinja2
An example with conditionals & loops from the Jinja templating docs

Jinja2 is a powerful prompting engine that allows for dynamic and adaptive prompt templates. In this article, we’ll be diving into Jinja and understanding how you can leverage it for your prompt templates.

So let’s dive into some of the basics of Jinja!

But first, what is Jinja?

Jinja2 is a pretty intuitive templating engine for Python. It is not all that difficult to learn and allows you to build within a template enabling conditional logic and loops without having to rely on an external language to do the work. Jinja works with all text-based formats (HTML, XML, CSV, LaTeX, etc.). However, it first became popular as an HTML templating language.

The Basics

At the lowest level, Jinja templating looks like a Python f-string, but with double curly braces.

Hello {{ name }}, welcome to our {{ service_name }} service.

In Jinja, variables/expressions are `{{enclosed in double curly brackets}}`. This allows us to do math within the brackets.

Your total score is {{ correct_answers / total_questions * 100 }}%.

Control structures such as loops and conditionals are then {% enclosed with curly brackets and parenthesis as shown %}. This would allow us to use templates such as the one below to check the user_type and iterate through items in a list.

{% if user_type == 'premium' %} 
  Welcome back, valued premium member! 
{% else %} 
  Welcome! Consider upgrading to our premium service. 
{% endif %} 
 
{% for item in todo_list %} 
  - {{ item }} 
{% endfor %}

There’s also inheritance in Jinja. You would simply use the extends keyword to have a template inherit content from another template. For example, this could be used by having a base template for a website page and the corresponding template that extends it to add details

Base template:

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>{% block title %}My Website{% endblock %}</title> 
</head> 
<body> 
    <header> 
        <h1>My Website</h1> 
        <nav> 
            <ul> 
                <li><a href="/">Home</a></li> 
                <li><a href="/about">About</a></li> 
                <li><a href="/contact">Contact</a></li> 
            </ul> 
        </nav> 
    </header> 
    <main> 
        {% block content %}{% endblock %} 
    </main> 
</body> 
</html>

About us page extending the base template:

{% extends "base.html" %} 
{% block title %}About Us{% endblock %} 
{% block content %} 
 <h2>About Us</h2> 
 <p>Welcome to the about page of this Website! Here you can learn more about who we are and what we do.</p> 
{% endblock %}

The last major concept we need to cover is a macro. They are the Jinja way of adding functions to your template. You could either define a macro in your file or import one from another file. Below I’ll show an example of creating a button macro that redirects you to a link.

{% macro button(text, link='#', color='blue') %} 
    <a href="{{ link }}" style="background-color: {{ color }}; padding: 10px; color: white; text-decoration: none;"> 
        {{ text }} 
    </a> 
{% endmacro %}

Here’s what calling that button would look like:

{% from "buttons.html" import button %}
<p>{{ button('Home', link='/', color='green') }}</p>
<p>{{ button('About', link='/about', color='blue') }}</p>
<p>{{ button('Contact', link='/contact', color='red') }}</p>

Macros are less important within prompting, but still handy to know just in case.

Putting it all together:

Now let us put together a complex prompt for an LLM using Jinja. In this example, we are trying to prompt an LLM with a patient’s condition and receive an accurate diagnosis.

A Jinja template saved within the PromptLayer prompt registry

You can see how data would logically get sorted by patient to create a pretty awesome and well-written prompt, no matter what the patient’s current condition is.

The why — Where Jinja stands apart:

You might be thinking, why use Jinja? There are a couple of parts where it stands out:

  1. In-line Business Logic

In-line logic within prompts enables moving complex logic into the prompt CMS and out of the code base. This approach enables simple logic like loops and conditionals to be handled within the prompt itself. Abstracting the prompt from the code base then helps streamline workflow, improve testing, and reduce redundancies in the code base!

2. Simplicity

Jinja is pretty simple to pick up and LLMs are quite adept at spitting out the exact template you ask them for in Jinja. Combined with the power these templates can have with the built-in logic, it can save a lot of time in the long run. On top of that, it supports so many text formats that it is extremely easy to use across a variety of use cases.

3. Performance

Jinja is extremely lightweight, which is great for saving time with multiple prompting calls.

Now that being said, there still is a debate on using templating languages or sticking to the original coding language to write in the logic. Despite Jinja’s advantages, many developers still prefer using programmatic logic and static/f-string prompts. At the end of the day, it is up to you to decide what works best for you!

No matter whether you choose Jinja or not for your prompting journey, PromptLayer would love to help optimize the process for you!


PromptLayer is a prompt management system that helps you iterate on prompts faster — further speeding up the development cycle! Use their prompt CMS to update a prompt, run evaluations, and deploy it to production in minutes. Check them out here. 🍰

Read more