Jinja2 template

In this chapter, you will learn to configure the Jinja2 template engine in FastAPI, using static files and template inheritance to build complete HTML pages.


FastAPI's two rendering modes

FastAPI returns JSON by default (suitable for APIs), but it can also return HTML (suitable for SSR).

The two modes can coexist—the same project can provide both a JSON API and render web pages.


Mount static files

Static files (CSS, JS, images) are handled throughStaticFilesMount to the specified path.

Example

# File path: main.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

# Mount the static/ directory to the /static path
# Access /static/css/style.css → actually reads static/css/style.css
app.mount("/static", StaticFiles(directory="static"), name="static")

Referencing static files in templates:

Example

<link rel="stylesheet" href="/static/css/style.css">
<img src="/static/images/logo.png">

Configure Jinja2 templates

Example

# File path: main.py
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")

# Specify template directory
templates = Jinja2Templates(directory="templates")

@app.get("/")
def index(request: Request):       # Note: The template route must receive a Request parameter.
    """Blog home page"""
    return templates.TemplateResponse(
        "index.html",              # Template filename
        {                          # context data
            "request": request,    # request must be passed in (Jinja2Templates requirement)
            "title": "EXAMPLE blog"
        }
    )

FastAPI's template rendering has two key differences from Flask: 1. The view function must receiverequest: Requestparameter; 2.requestMust be passed to the template as context. If request is omitted, the url_for function in the template will fail.


Create the base.html parent template

Example

<!-- File path: templates/base.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}EXAMPLE Blog{% endblock %}</title>
    <link rel="stylesheet" href="/static/css/style.css">
    {% block extra_head %}{% endblock %}
</head>
<body>
    <header class="navbar">
        <a href="/" class="logo">EXAMPLE Blog (FastAPI)</a>
        <nav>
            <a href="/">Home</a>
            <a href="#">About</a>
        </nav>
    </header>

    <main class="container">
        {% block content %}{% endblock %}
    </main>

    <footer class="footer">
        <p>© 2024 EXAMPLE Blog. Powered by FastAPI.</p>
    </footer>
</body>
</html>

Create the index.html child template

Example

<!-- File path: templates/index.html -->
{% extends 'base.html' %}

{% block title %}{{ title }}{% endblock %}

{% block content %}
<h2 class="section-title">Latest Articles</h2>
<p>The article list will be displayed in later chapters.</p>
{% endblock %}

url_for() in FastAPI Templates

Similar to Flask, FastAPI also supportsurl_for(), but you need to name the route first.

Example

@app.get("/post/{post_id}", name="post_detail")   # name= names the route
def post_detail(request: Request, post_id: int):
    return templates.TemplateResponse("post_detail.html",
        {"request": request, ...})

Example

<!-- Reference in template -->
<a href="{{ url_for('post_detail', post_id=3) }}">Article 3</a>

Create basic CSS styles

Example

/* File path: static/css/style.css */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: #f5f5f5;
    color: #333;
}

.navbar {
    display: flex; justify-content: space-between; align-items: center;
    padding: 16px 40px; background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.navbar .logo {
    font-size: 22px; font-weight: bold;
    color: #009688; text-decoration: none;
}

.navbar nav a {
    margin-left: 20px; text-decoration: none; color: #333;
}

.container { max-width: 960px; margin: 40px auto; padding: 0 20px; }

.footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }

.section-title { font-size: 24px; margin-bottom: 20px; }

Chapter summary

In this chapter, you learned frontend rendering configuration in FastAPI: StaticFiles for mounting static resources, Jinja2Templates for configuring the template directory, TemplateResponse for returning HTML, and key differences from Flask in template rendering (the Request parameter must be passed in).

other extensions