When building web applications with FastAPI and Jinja2 templates, one of the most common issues developers face is template code duplication. Every HTML page tends to have similar boilerplate code: DOCTYPE declarations, meta tags, CSS links, JavaScript imports, and basic HTML structure. Writing this repeatedly across multiple templates is not only tedious but also makes maintenance a nightmare.
Today, let's explore how template inheritance in Jinja2 can transform your messy, repetitive templates into clean, maintainable code using the power of base.html.
The Problem: Code Duplication Everywhere
Here's what our templates/blogs/list.html file looks as of now:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    <title>Blog List</title>
</head>
<body>
    <h1 class="text-3xl font-bold text-center">Blog List</h1>
</body>
</html>
Let us extract out the common parts in a new file named templates/base.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    {% block title %}
    {% endblock title %}
    {% block head %}
    {% endblock head %}
</head>
<body>
    {% block body %}
    {% endblock body %}
</body>
</html>
Understanding Jinja2 Template Inheritance
Key Concepts
1. {% extends %} Tag
{% extends "base.html" %}
This tells Jinja2 that this template inherits from base.html. It must be the first tag in your template.
2. {% block %} Tags
{% block title %}
    <title>Custom Title</title>
{% endblock title %}
Blocks are placeholders in the base template that child templates can override. The base template defines the blocks, and child templates provide the content.
The New list.html:
Now, our blog list page becomes incredibly simple:
{% extends "base.html" %}
{% block title %}
<title>Blog List</title>
{% endblock title %}
{% block body %}
<h1 class="text-3xl font-bold text-center">Blog List</h1>
{% endblock body %}
What we are doing is injecting the contents inside the base.html and doing a final rendering of the HTML.
Common block names include:
title- for page titlesbodyorcontent- for main contentscripts- for page-specific JavaScriptextra_head- for additional head elementssidebar- for sidebar content