Templates and static files — the basics
How Django finds the right HTML file to render, the small set of template tags that get used constantly, and how CSS/JS/images actually reach the browser.
3 min read
Where Django looks for templates
myapp/
templates/
myapp/
article_list.html
article_detail.html
By default, Django looks for templates inside a templates/ folder within each app. Nesting an extra folder named after the app itself (templates/myapp/...) is a deliberate, near-universal convention, not an accident — without it, two different apps that both happen to have a detail.html template would collide, since Django searches across every installed app's templates/ folder as one combined namespace. render(request, "myapp/article_detail.html", context) in a view is what actually loads and renders one of these files.
Template inheritance: not repeating the same HTML shell everywhere
{# base.html #}
<!DOCTYPE html>
<html>
<head><title>{% block title %}My Site{% endblock %}</title></head>
<body>
<nav>...</nav>
{% block content %}{% endblock %}
</body>
</html>{# article_detail.html #}
{% extends "myapp/base.html" %}
{% block title %}{{ article.title }}{% endblock %}
{% block content %}
<h1>{{ article.title }}</h1>
<p>{{ article.body }}</p>
{% endblock %}{% extends %} and {% block %} are how Django avoids copy-pasting the same <html>/<head>/navigation markup into every single page template. base.html defines the overall page shell with named, empty {% block %} sections; any template that extends it fills in those specific blocks, inheriting everything else from the parent automatically. This is the template-layer equivalent of the class inheritance covered in the OOP domain — a child template overrides specific named sections while reusing the rest, the same "override just what's different, inherit the rest" shape.
Including a reusable snippet
{# navbar.html #}
<nav><a href="/">Home</a> | <a href="/articles/">Articles</a></nav>{% include "myapp/navbar.html" %}{% include %} inserts one template directly inside another — useful for a genuinely reusable fragment (a navbar, a footer, a single article "card" repeated in a list) that isn't a full page shell the way {% extends %}'s base template is. The rule of thumb: {% extends %} for "this page's overall skeleton," {% include %} for "this smaller, reusable chunk."
Static files: CSS, JavaScript, and images
myapp/
static/
myapp/
style.css
script.js
{% load static %}
<link rel="stylesheet" href="{% static 'myapp/style.css' %}">CSS, JavaScript, and image files are static files — content served as-is, not rendered through the template engine. They live in a static/ folder (mirroring the same app-namespaced structure as templates/, for the same reason), and {% static 'path' %} — after {% load static %} at the top of the template — generates the correct URL to reference one. Using {% static %} instead of hardcoding a path like /static/myapp/style.css directly matters because the actual URL static files are served from can be configured differently in production (often served by a separate web server or CDN entirely, not Django itself) — the tag generates whatever URL is currently correct, rather than a path that might be wrong once deployed.
Why static files need {% load static %} and templates don't need {% load %} at all for basic tags
{% load static %} loads the static template tag library — Django's basic built-in tags (if, for, block, extends) are always available, but more specialized tag sets are grouped into libraries that have to be explicitly loaded before use, keeping the always-available core tag set small and avoiding naming collisions between different libraries' tags. Forgetting {% load static %} and then using {% static %} anyway raises a clear template syntax error rather than silently failing, which makes this specific mistake quick to spot and fix.
Further reading
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why do Django templates conventionally live at templates/myapp/template.html, not templates/template.html?
2. What's the difference between {% extends %} and {% include %}?
3. Why use {% static 'myapp/style.css' %} instead of hardcoding /static/myapp/style.css?
4. What has to happen before {% static %} can be used in a template?