Skip to main content
Flask provides functions to render Jinja2 templates with context data.

Template Rendering

render_template

render_template(
    template_name_or_list: str | Template | list[str | Template],
    **context: Any
) -> str
Render a template by name with the given context.
template_name_or_list
str | Template | list[str | Template]
required
The name of the template to render. If a list is given, the first name to exist will be rendered.
context
Any
The variables to make available in the template as keyword arguments.
Returns: The rendered template as a string. Example
from flask import render_template

@app.route('/')
def index():
    return render_template('index.html', title='Home', user='John')

@app.route('/profile/<username>')
def profile(username):
    user = get_user(username)
    return render_template(
        'profile.html',
        user=user,
        posts=user.get_posts(),
        followers=user.get_followers()
    )

# Render first available template
@app.route('/error')
def error():
    return render_template(
        ['errors/custom.html', 'errors/default.html'],
        error_code=500
    )

render_template_string

render_template_string(source: str, **context: Any) -> str
Render a template from the given source string with the given context.
source
str
required
The source code of the template to render.
context
Any
The variables to make available in the template as keyword arguments.
Returns: The rendered template as a string.
Never render template strings from untrusted user input. This can lead to security vulnerabilities.
Example
from flask import render_template_string

@app.route('/hello/<name>')
def hello(name):
    template = '<h1>Hello {{ name }}!</h1>'
    return render_template_string(template, name=name)

# Render dynamic email template
@app.route('/send-email')
def send_email():
    email_template = get_email_template_from_db()
    content = render_template_string(
        email_template,
        user=current_user,
        action_url=url_for('confirm_email', _external=True)
    )
    send_mail(current_user.email, content)
    return 'Email sent'

Streaming Templates

stream_template

stream_template(
    template_name_or_list: str | Template | list[str | Template],
    **context: Any
) -> Iterator[str]
Render a template by name with the given context as a stream. This returns an iterator of strings, which can be used as a streaming response from a view.
template_name_or_list
str | Template | list[str | Template]
required
The name of the template to render. If a list is given, the first name to exist will be rendered.
context
Any
The variables to make available in the template as keyword arguments.
Returns: An iterator of strings.
Added in version 2.2
Example
from flask import stream_template, Response

@app.route('/large-report')
def large_report():
    # Stream a large template to avoid loading it all in memory
    return Response(stream_template(
        'report.html',
        data=get_large_dataset(),
        title='Annual Report'
    ))

@app.route('/logs')
def stream_logs():
    def generate_logs():
        for log in get_log_entries():
            yield log
    
    return Response(stream_template(
        'logs.html',
        logs=generate_logs()
    ))

stream_template_string

stream_template_string(source: str, **context: Any) -> Iterator[str]
Render a template from the given source string with the given context as a stream. This returns an iterator of strings, which can be used as a streaming response from a view.
source
str
required
The source code of the template to render.
context
Any
The variables to make available in the template as keyword arguments.
Returns: An iterator of strings.
Added in version 2.2
Example
from flask import stream_template_string, Response

@app.route('/generate')
def generate():
    template = '''
    <html>
    <head><title>{{ title }}</title></head>
    <body>
    {% for item in items %}
        <p>{{ item }}</p>
    {% endfor %}
    </body>
    </html>
    '''
    
    return Response(stream_template_string(
        template,
        title='Generated Page',
        items=get_large_item_list()
    ))

Template Environment

Environment

class Environment(BaseEnvironment)
Works like a regular Jinja2 environment but has some additional knowledge of how Flask’s blueprint works so that it can prepend the name of the blueprint to referenced templates if necessary. Example
from flask.templating import Environment

# The environment is created automatically by Flask
# Access it via app.jinja_env

@app.before_first_request
def configure_template_env():
    # Add custom filters
    app.jinja_env.filters['reverse'] = lambda s: s[::-1]
    
    # Add custom globals
    app.jinja_env.globals['app_name'] = 'My Application'
    
    # Configure auto-escaping
    app.jinja_env.autoescape = True

DispatchingJinjaLoader

class DispatchingJinjaLoader(BaseLoader)
A loader that looks for templates in the application and all the blueprint folders. This is used internally by Flask and typically doesn’t need to be used directly. Example
from flask.templating import DispatchingJinjaLoader

# Flask automatically creates this loader
# It searches for templates in:
# 1. Application template folder
# 2. Blueprint template folders

# Template lookup order:
# - app/templates/page.html
# - blueprint1/templates/page.html  
# - blueprint2/templates/page.html

Template Context

Flask automatically makes several objects available in the template context:
  • config - The current configuration object
  • request - The current request object
  • session - The current session object
  • g - The request-bound object for global variables
  • url_for() - The url_for function
  • get_flashed_messages() - The get_flashed_messages function
Example
<!-- In your template -->
<h1>{{ config['APP_NAME'] }}</h1>

{% if request.method == 'POST' %}
  <p>Form submitted</p>
{% endif %}

{% if session.user_id %}
  <p>Welcome, user {{ session.user_id }}!</p>
{% endif %}

<a href="{{ url_for('profile', username=g.user.name) }}">Profile</a>

{% with messages = get_flashed_messages() %}
  {% if messages %}
    {% for message in messages %}
      <p>{{ message }}</p>
    {% endfor %}
  {% endif %}
{% endwith %}

Custom Context Processors

You can add your own variables to the template context using context processors: Example
@app.context_processor
def inject_user():
    return dict(current_user=get_current_user())

@app.context_processor  
def utility_processor():
    def format_price(amount):
        return f"${amount:.2f}"
    return dict(format_price=format_price)

# Now available in all templates:
# {{ current_user.name }}
# {{ format_price(19.99) }}

Template Filters

Add custom filters to process template variables: Example
@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

@app.template_filter('pluralize')
def pluralize_filter(count, singular, plural):
    return singular if count == 1 else plural

# Usage in templates:
# {{ "hello" | reverse }} -> "olleh"
# {{ count | pluralize('item', 'items') }}

Template Tests

Add custom tests for template conditions: Example
@app.template_test('prime')
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

# Usage in templates:
# {% if value is prime %}
#   {{ value }} is a prime number
# {% endif %}

Build docs developers (and LLMs) love