Skip to main content

Templating & Static Assets

Flask integrates with the Jinja2 templating engine to render dynamic HTML and other text formats. It provides a custom environment that automatically handles template loading from both the application and its registered blueprints, while injecting essential context variables like request, session, and g.

Rendering Templates

To render a template file, use the render_template function. It looks for the file in the folders configured by the application and blueprints, renders it with the provided context, and returns the resulting string.

from flask import render_template

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

Internally, render_template retrieves the Jinja environment from app.jinja_env and calls get_or_select_template. If you pass a list of names, it will render the first one that exists.

Rendering from Strings

If you have a template string instead of a file, use render_template_string. This is useful for small, dynamic templates or when templates are stored in a database.

from flask import render_template_string

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

Streaming Templates

For large responses, such as a massive data table, stream_template allows you to render the template as an iterator of strings. This prevents the entire rendered string from being held in memory at once.

from flask import stream_template

@app.route("/large-report")
def report():
data = generate_large_dataset()
return stream_template("report.html", rows=data)

This function uses Jinja's template.generate and wraps it in stream_with_context to ensure the application context remains available during the entire streaming process.

Template Context

Flask automatically injects several variables into the template context. These are available in every template without being explicitly passed to render_template:

  • config: The current application's configuration object.
  • request: The current request object.
  • session: The current session object.
  • g: The flask.g object for request-global storage.
  • url_for(): The function for generating URLs.
  • get_flashed_messages(): The function to retrieve flashed messages.

Context Processors

You can inject additional variables into all templates using the @app.context_processor decorator. The decorated function must return a dictionary.

@app.context_processor
def inject_user():
return dict(user=g.user if "user" in g else None)

Flask's update_template_context method in src/flask/app.py handles this injection. It iterates through the processors of the application and the active blueprint (if any), ensuring that values passed directly to render_template take precedence over those from processors.

Template Loading and Blueprints

Flask uses a DispatchingJinjaLoader (defined in src/flask/templating.py) to locate templates. This loader searches for templates in the following order:

  1. The application's template_folder (defaulting to templates/).
  2. The template_folder of each registered blueprint, in the order they were registered.

Overriding Blueprint Templates

Because the application's template folder is searched first, you can override a blueprint's template by creating a file with the same path in your application's templates folder. For example, if a blueprint named auth expects a template at auth/login.html, you can provide your own version at yourapp/templates/auth/login.html.

Debugging Template Loading

If you encounter TemplateNotFound errors, you can enable EXPLAIN_TEMPLATE_LOADING in your config. When set to True, Flask will log every attempt to find a template, showing which loaders were queried and which paths were checked.

app.config["EXPLAIN_TEMPLATE_LOADING"] = True

Static Assets

Flask automatically serves static files (like CSS, JavaScript, and images) from a folder named static located next to your application module or inside your package.

Configuration

The behavior is controlled by two parameters in the Flask or Blueprint constructor:

  • static_folder: The directory containing static files. Defaults to 'static'.
  • static_url_path: The URL prefix for static files. Defaults to the name of the static_folder.

Generating Static URLs

Always use url_for with the 'static' endpoint to generate URLs for your assets. This ensures that if you change your static_url_path or move your assets to a CDN, your templates won't break.

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">

Serving Files Internally

The send_static_file method is the underlying view function for the /static route. It uses werkzeug.utils.send_from_directory to safely serve files, ensuring that requested paths do not escape the configured static folder.

Customizing the Environment

You can extend Jinja's functionality by registering custom filters, globals, and tests directly on the application object.

Custom Filters

Filters are used to transform data within templates using the pipe (|) syntax.

@app.template_filter("reverse")
def reverse_filter(s):
return s[::-1]

Custom Globals

Globals are functions or variables available directly in the template namespace.

@app.template_global()
def current_year():
return datetime.datetime.now().year

Custom Tests

Tests are used with the is keyword to check conditions.

@app.template_test("even")
def is_even(n):
return n % 2 == 0

These decorators call add_template_filter, add_template_global, and add_template_test respectively, which modify the jinja_env directly. For example, add_template_filter simply sets self.jinja_env.filters[name] = f.