Server-side rendering with Jinja templates
Lesson 4 of 5
4Server-side rendering with Jinja templates
The big pictureIn SSR the browser does not receive JSON and draw it itself. The server fills a template with data and sends final HTML, so the page shows as soon as it arrives, even without JavaScript.
What the picture shows: A request's journey in SSR: the server does the drawing. The browser receives a complete page and shows it straight away.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
Picture a restaurant: in SSR the kitchen cooks the whole dish and sends it ready to your table. The other way, it sends you the ingredients and you cook at the table (JavaScript in the browser). The ready dish reaches your mouth sooner, especially when your table (your phone) is slow.
A template engine (Jinja2 in Flask, a close syntax in Django) evaluates {{ expr }}, {% for %} and {% if %} and auto-escapes, so < becomes <. Inheritance with {% extends "base.html" %} and {% block %} gives every page one frame. SSR improves first contentful paint and indexing, costs server work per request, and is usually paired with caching or static generation, or with hydration when you need heavy interactivity.
Before You Start
📨HTTP
You know requests, responses and status codes.
🐍Python and functions
You write a function and pass it a dictionary.
The Core Idea
1A template: text with blanks
A template is an HTML file with places for data. The engine swaps each place for its value. Here it is with the standard library so you see the bare idea, then Jinja.
from string import Template
from html import escape
page = Template("<h1>$title</h1>\n<ul>\n$items</ul>")
menu = ["Espresso", "Latte", "<script>alert(1)</script>"]
items = "".join(f" <li>{escape(name)}</li>\n" for name in menu)
print(page.substitute(title="Menu", items=items))<script> becomes code running in every visitor's browser (XSS). Jinja escapes automatically, so do not switch it off with |safe except for text you fully trust.2Jinja: loops, conditions and inheritance
{{ }} prints a value and {% %} controls flow. The base template defines the frame and the blocks; each page fills only the blocks.
{# templates/base.html #}
<!doctype html>
<html lang="ar" dir="rtl">
<head><title>{% block title %}مقهى{% endblock %}</title></head>
<body>
<nav><a href="/">الرئيسية</a></nav>
<main>{% block content %}{% endblock %}</main>
</body>
</html>
{# templates/menu.html #}
{% extends "base.html" %}
{% block title %}القائمة{% endblock %}
{% block content %}
<h1>القائمة</h1>
{% if drinks %}
<ul>
{% for d in drinks %}
<li>{{ d.name }}: {{ d.price }} ر.س</li>
{% endfor %}
</ul>
{% else %}
<p>القائمة فارغة اليوم.</p>
{% endif %}
{% endblock %}3Flask: a route renders a template
The route loads the data and passes it to render_template. The reply is full HTML with status 200.
from flask import Flask, render_template, abort
app = Flask(__name__)
DRINKS = {1: {"name": "Latte", "price": 14}, 2: {"name": "Mocha", "price": 16}}
@app.get("/menu")
def menu():
return render_template("menu.html", drinks=list(DRINKS.values()))
@app.get("/drinks/<int:drink_id>")
def drink(drink_id):
item = DRINKS.get(drink_id)
if item is None:
abort(404)
return render_template("drink.html", drink=item)
# flask --app app run --debug4When SSR and when a single-page app?
SSR for content people read and search: shops, blogs, product pages, simple admin panels. A single-page app for highly interactive tools: an editor, a map, a live chart board. Modern frameworks like Next.js mix both: the server draws first, then React takes over interaction.
Worked example
Problem: a React product page stays blank for two seconds on a slow phone, and the search engine cannot see the names. Analysis: the browser loads JS, then asks for JSON, then draws. Fix: render the page on the server with a template that fills in names and prices, so HTML arrives ready. Interactive buttons (add to cart) stay as a little JS on top.
Myth vs Reality
| Myth | Reality |
|---|---|
| SSR is an old technique that is over. | It came back strong: Next.js, Remix, Django and Rails all render on the server, because speed and indexing matter. |
| SSR means no JavaScript at all. | It means the first page arrives ready. You can add JS for interaction on top. |
Test your understanding
Who builds the HTML in SSR?
The server fills the template and sends ready HTML.
A product name holding <script> is shown in Jinja without |safe. What happens?
Auto-escaping turns < into < so nothing runs.
What is {% extends %} for?
One frame for all pages, and each page writes only its own part.
Quick review cards
Check Your Understanding
Why is SSR better for search?
Because the content is in the HTML sent itself, so a crawler need not run JavaScript to see it.
What does SSR cost?
Server work on every request. We ease it with caching or static generation for pages that do not change.
When do you pick an SPA?
For a highly interactive tool where the user stays long, like an editor or a live chart board.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Official docs2
Done with this lesson?
Sign in to save your progress.