Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Jinja
https://github.com/pallets/jinja
Admin
A very fast and expressive template engine.
Tokens:
23,436
Snippets:
193
Trust Score:
8.8
Update:
5 months ago
Context
Skills
Chat
Benchmark
87.9
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Jinja2 Template Engine Jinja2 is a fast, expressive, and extensible template engine written in pure Python. It provides a Django-inspired non-XML syntax that supports inline expressions and an optional sandboxed environment for safely rendering untrusted templates. The engine compiles templates to optimized Python code with caching support, making it suitable for high-performance web applications. The library includes template inheritance, macros, filters, tests, autoescaping for security, async/await support, and internationalization (i18n) capabilities. It features multiple loader types for loading templates from files, dictionaries, packages, and custom sources. Jinja2 separates business logic from presentation while providing powerful template composition features like blocks, includes, and imports. ## Basic Template Rendering Render a template from a string with variable substitution. ```python from jinja2 import Environment, DictLoader env = Environment(loader=DictLoader({ "greeting.html": "Hello {{ name }}! You have {{ count }} messages." })) template = env.get_template("greeting.html") output = template.render(name="Alice", count=5) print(output) # Output: Hello Alice! You have 5 messages. ``` ## Template Inheritance with Blocks Create template hierarchies using extends and block tags for reusable layouts. ```python from jinja2 import Environment, DictLoader env = Environment(loader=DictLoader({ "base.html": """ <!doctype html> <html> <head><title>{% block title %}Default Title{% endblock %}</title></head> <body>{% block content %}{% endblock %}</body> </html> """, "page.html": """ {% extends "base.html" %} {% block title %}My Page{% endblock %} {% block content %}<h1>Welcome</h1><p>Content here</p>{% endblock %} """ })) template = env.get_template("page.html") print(template.render()) # Output: Full HTML page with inherited structure and custom content ``` ## FileSystemLoader for Template Files Load templates from the filesystem with automatic change detection and caching. ```python from jinja2 import Environment, FileSystemLoader, select_autoescape env = Environment( loader=FileSystemLoader("templates"), autoescape=select_autoescape(["html", "xml"]), cache_size=400, auto_reload=True ) try: template = env.get_template("user_profile.html") output = template.render( user={"name": "Bob", "email": "bob@example.com", "active": True} ) print(output) except Exception as e: print(f"Error: {e}") ``` ## Custom Filters Register custom filters to transform variables in templates. ```python from jinja2 import Environment, DictLoader def reverse_string(value): return value[::-1] def format_currency(value): return f"${value:,.2f}" env = Environment(loader=DictLoader({ "invoice.html": "Total: {{ amount | currency }} - Code: {{ code | reverse }}" })) env.filters["reverse"] = reverse_string env.filters["currency"] = format_currency template = env.get_template("invoice.html") print(template.render(amount=1234.567, code="ABC123")) # Output: Total: $1,234.57 - Code: 321CBA ``` ## Macros for Reusable Components Define reusable template functions with macros. ```python from jinja2 import Environment, DictLoader env = Environment(loader=DictLoader({ "macros.html": """ {% macro input_field(name, type="text", placeholder="") %} <div class="form-group"> <input type="{{ type }}" name="{{ name }}" placeholder="{{ placeholder }}" class="form-control"> </div> {% endmacro %} """, "form.html": """ {% import "macros.html" as forms %} <form> {{ forms.input_field("username", placeholder="Enter username") }} {{ forms.input_field("password", type="password", placeholder="Enter password") }} {{ forms.input_field("email", type="email", placeholder="Enter email") }} </form> """ })) template = env.get_template("form.html") print(template.render()) # Output: Complete HTML form with three input fields ``` ## Loop Iteration with Control Flow Iterate over collections with loop variables and conditional logic. ```python from jinja2 import Environment, DictLoader env = Environment(loader=DictLoader({ "products.html": """ <ul> {% for product in products %} <li class="{{ 'featured' if product.featured else 'regular' }}"> {{ loop.index }}. {{ product.name }} - ${{ product.price }} {% if loop.first %}(First){% endif %} {% if loop.last %}(Last){% endif %} </li> {% else %} <li>No products available</li> {% endfor %} </ul> """ })) template = env.get_template("products.html") products = [ {"name": "Laptop", "price": 999, "featured": True}, {"name": "Mouse", "price": 25, "featured": False}, {"name": "Keyboard", "price": 75, "featured": False} ] print(template.render(products=products)) # Output: Numbered list with loop metadata ``` ## Autoescaping for Security Automatically escape HTML to prevent XSS attacks from untrusted input. ```python from jinja2 import Environment, DictLoader, select_autoescape from markupsafe import Markup env = Environment( loader=DictLoader({ "comment.html": """ <div class="comment"> <p>{{ username }} says:</p> <p>{{ message }}</p> <p>Safe HTML: {{ safe_html }}</p> </div> """ }), autoescape=select_autoescape(["html", "xml"]) ) template = env.get_template("comment.html") print(template.render( username="<script>alert('xss')</script>", message="Hello <b>world</b>", safe_html=Markup("<em>This is safe</em>") )) # Output: Malicious script tags escaped, safe HTML preserved ``` ## Sandboxed Environment Execute untrusted templates safely with restricted access to Python internals. ```python from jinja2.sandbox import SandboxedEnvironment from jinja2 import DictLoader env = SandboxedEnvironment(loader=DictLoader({ "user_template.html": """ <p>User: {{ user.name }}</p> <p>Items: {{ items | length }}</p> """ })) template = env.get_template("user_template.html") try: output = template.render( user={"name": "Alice", "password": "secret123"}, items=[1, 2, 3, 4, 5] ) print(output) except Exception as e: print(f"Security error: {e}") # Output: Safe rendering without access to dangerous attributes ``` ## Custom Global Functions Add global functions accessible from all templates. ```python from jinja2 import Environment, DictLoader import datetime def now(): return datetime.datetime.now() def range_check(value, min_val, max_val): return min_val <= value <= max_val env = Environment(loader=DictLoader({ "report.html": """ Report generated at: {{ now().strftime('%Y-%m-%d %H:%M:%S') }} Score: {{ score }} - {{ 'PASS' if range_check(score, 60, 100) else 'FAIL' }} """ })) env.globals["now"] = now env.globals["range_check"] = range_check template = env.get_template("report.html") print(template.render(score=75)) # Output: Report with current timestamp and pass/fail status ``` ## Template Context Access with pass_context Access the template context in custom filters and functions. ```python from jinja2 import Environment, DictLoader, pass_context @pass_context def current_user_filter(context, message): username = context.get("current_user", "Guest") return f"[{username}] {message}" env = Environment(loader=DictLoader({ "message.html": "{{ text | user_prefix }}" })) env.filters["user_prefix"] = current_user_filter template = env.get_template("message.html") print(template.render(text="Hello World", current_user="Alice")) # Output: [Alice] Hello World print(template.render(text="Hello World")) # Output: [Guest] Hello World ``` ## NativeEnvironment for Python Types Render templates that return native Python types instead of strings. ```python from jinja2.nativetypes import NativeEnvironment, NativeTemplate env = NativeEnvironment() # Return integers template = env.from_string("{{ 40 + 2 }}") result = template.render() print(f"{result} (type: {type(result).__name__})") # Output: 42 (type: int) # Return lists template = env.from_string("[{% for i in range(3) %}{{ i }}{{ ',' if not loop.last }}{% endfor %}]") result = template.render() print(f"{result} (type: {type(result).__name__})") # Output: [0, 1, 2] (type: list) # Return dictionaries template = env.from_string("{'name': '{{ name }}', 'age': {{ age }}}") result = template.render(name="Alice", age=30) print(f"{result} (type: {type(result).__name__})") # Output: {'name': 'Alice', 'age': 30} (type: dict) ``` ## Async Template Rendering Render templates asynchronously with async/await support. ```python import asyncio from jinja2 import Environment, DictLoader async def fetch_user_data(user_id): await asyncio.sleep(0.1) # Simulate async operation return {"id": user_id, "name": f"User{user_id}", "status": "active"} env = Environment( loader=DictLoader({ "user.html": """ User: {{ user.name }} Status: {{ user.status }} """ }), enable_async=True ) async def render_async(): template = env.get_template("user.html") user_data = await fetch_user_data(123) output = await template.render_async(user=user_data) print(output) asyncio.run(render_async()) # Output: User: User123, Status: active ``` ## ChainableUndefined for Lenient Access Use ChainableUndefined to handle missing attributes gracefully without errors. ```python from jinja2 import Environment, DictLoader, ChainableUndefined env = Environment( loader=DictLoader({ "profile.html": """ Name: {{ user.name }} Address: {{ user.address.city }} Phone: {{ user.contact.phone }} """ }), undefined=ChainableUndefined ) template = env.get_template("profile.html") print(template.render(user={"name": "Alice"})) # Output: Name: Alice, Address: (empty), Phone: (empty) # No errors raised for missing nested attributes ``` ## Compile Templates to Bytecode Pre-compile templates for faster loading and execution. ```python from jinja2 import Environment, FileSystemLoader from jinja2.bccache import FileSystemBytecodeCache import tempfile import os cache_dir = tempfile.mkdtemp() template_dir = tempfile.mkdtemp() # Create a template file with open(os.path.join(template_dir, "example.html"), "w") as f: f.write("Hello {{ name }}!") env = Environment( loader=FileSystemLoader(template_dir), bytecode_cache=FileSystemBytecodeCache(cache_dir), auto_reload=False ) template = env.get_template("example.html") print(template.render(name="World")) # Output: Hello World! # Bytecode cached in cache_dir for faster subsequent loads ``` ## Custom Extensions Extend Jinja2 syntax by creating custom extensions. ```python from jinja2 import Environment, DictLoader from jinja2.ext import Extension from jinja2 import nodes class UppercaseExtension(Extension): tags = {"upper"} def parse(self, parser): lineno = next(parser.stream).lineno body = parser.parse_statements(["name:endupper"], drop_needle=True) return nodes.CallBlock( self.call_method("_uppercase", []), [], [], body ).set_lineno(lineno) def _uppercase(self, caller): return caller().upper() env = Environment( loader=DictLoader({ "test.html": "{% upper %}hello world{% endupper %}" }), extensions=[UppercaseExtension] ) template = env.get_template("test.html") print(template.render()) # Output: HELLO WORLD ``` ## Summary Jinja2 serves as a comprehensive template engine for web applications, configuration generation, code generation, email templates, and static site generation. The library excels at separating presentation logic from business logic while maintaining powerful expression capabilities through filters, tests, and control structures. Common use cases include rendering HTML pages in web frameworks (Flask, Django), generating configuration files with variable substitution, creating email templates with personalization, and building static documentation sites. Integration patterns include using FileSystemLoader for file-based templates with auto-reloading in development, DictLoader for testing and dynamic templates, PackageLoader for templates bundled with Python packages, and custom loaders for database-backed templates. The SandboxedEnvironment provides secure rendering of untrusted user content, while NativeEnvironment enables configuration file generation that produces Python data structures. For production deployments, bytecode caching significantly improves performance, and template pre-compilation eliminates runtime parsing overhead. The library integrates seamlessly with async frameworks through enable_async mode and supports internationalization through the i18n extension with Babel.