ABHIJAT
← Back to Writing

AI Engineering

Jinja2 templates for LLM prompts instead of string concatenation

Prompt strings built with f-strings and concatenation get unreadable fast. A templating engine built for this exact problem already exists.

Abhijat2026-094 min read5 views

Last updated September 17, 2026

Prompt construction usually starts as an f-string, and stays an f-string well past the point where it should have moved to something else — a prompt with several optional sections, a variable-length list of examples, and conditional instructions depending on context ends up as a tangle of string concatenation and inline conditionals that's hard to read and harder to modify without breaking something adjacent.

Where it breaks down

prompt = f"You are a helpful assistant.\n"
if context:
    prompt += f"Context: {context}\n"
if examples:
    prompt += "Examples:\n"
    for ex in examples:
        prompt += f"- {ex}\n"
prompt += f"Question: {question}"

This is manageable at four lines and unmanageable at forty, once there are several more conditional sections and the indentation and string-building logic have to be tracked mentally to know what the final prompt actually looks like for any given combination of inputs.

Jinja2 was built for exactly this shape of problem

from jinja2 import Template

prompt_template = Template("""
You are a helpful assistant.
{% if context %}
Context: {{ context }}
{% endif %}
{% if examples %}
Examples:
{% for ex in examples %}
- {{ ex }}
{% endfor %}
{% endif %}
Question: {{ question }}
""")

prompt = prompt_template.render(context=context, examples=examples, question=question)

The conditionals and loops live in the template, declaratively, instead of scattered through imperative Python string-building — the template reads like the actual shape of the final prompt, with the logic for which sections appear inline where those sections belong, not four lines away in a separate if block.

The bigger win: prompts stop living inside application code

The less obvious benefit is that templates can move to their own files, which means prompt text is no longer physically interleaved with application logic. That separation makes prompts something that can be diffed cleanly, reviewed by someone who doesn't need to read Python to evaluate the wording, and versioned independently of the code that calls them — which matters a lot once prompt iteration is a regular activity involving people other than whoever originally wrote the surrounding function.

This isn't a case for a heavier abstraction than the problem needs — a single, simple prompt with no conditionals is still fine as an f-string. It's specifically once a prompt has real conditional structure that a templating engine designed for exactly that stops being overkill and starts being the thing that keeps the prompt readable.

Tags

Jinja2Prompt EngineeringPython