In Django's TEMPLATES setting, what do DIRS and APP_DIRS do, and in what order does Django search for a template name?
answer
- project folders versus app folders
- one loader per source
- first match wins
- INSTALLED_APPS order matters
- a subfolder named after the app
basics
~10 sDIRS lists project template directories searched first, in order; APP_DIRS=True adds each installed app's templates/ subdirectory, searched in INSTALLED_APPS order. Django uses the first file that matches and raises TemplateDoesNotExist if none does.
solid answer
~40 s`TEMPLATES` is a list of engine configurations; with the `DjangoTemplates` backend, `DIRS` is a list of directories the filesystem loader searches **in the order given**, and `APP_DIRS: True` adds the app-directories loader, which looks in the `templates/` subdirectory of every app in `INSTALLED_APPS`, **in INSTALLED_APPS order**. By default the filesystem loader runs first, so a project-level `templates/admin/base_site.html` in `DIRS` overrides the admin's own copy. The first match wins; if nothing matches, `TemplateDoesNotExist` is raised and the debug page lists every path tried. `APP_DIRS` defaults to `False`, though `startproject` sets it to `True`. Because all app template folders share one namespace, put an app's templates under `templates/<app_label>/` so two apps' `detail.html` files never shadow each other.
code
python · 11 linesTEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
BASE_DIR / "templates" / "overrides", # searched first
BASE_DIR / "templates",
],
"APP_DIRS": True, # then <app>/templates/ in INSTALLED_APPS order
"OPTIONS": {"context_processors": ["django.template.context_processors.request"]},
},
]go deeper
Know that DIRS holds project template folders, APP_DIRS searches each app's templates folder, and the first match wins.
Explain loader order — filesystem over DIRS, then app directories in INSTALLED_APPS order — and why app templates live in a subfolder named after the app.
Use search order deliberately to override third-party templates, and debug missing templates from the loader postmortem instead of guessing.
Set template-layout conventions (project overrides, namespaced app folders) so reusable apps and per-tenant overrides never shadow each other by accident.
## The TEMPLATES setting `TEMPLATES` is a **list of engine configurations**. Its default in Django's global settings is an empty list; the `settings.py` that `startproject` generates contains one entry: ```python TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] ``` (The generated file ships `DIRS` empty; adding a project-level folder as above is the usual first edit.) | Key | Meaning | Default | |---|---|---| | `BACKEND` | engine class: `DjangoTemplates` or `Jinja2` | required | | `DIRS` | directories to search, in order | `[]` | | `APP_DIRS` | also search inside installed apps | `False` (startproject sets `True`) | | `OPTIONS` | backend-specific options: `context_processors`, `loaders`, `debug`, `autoescape`, `libraries`, ... | `{}` | ## How a name is resolved When a view asks for `"storefront/home.html"`, the `DjangoTemplates` engine runs its **template loaders** in order. With `DIRS` and `APP_DIRS` set and no explicit `loaders` option, that order is: 1. the **filesystem loader**, trying each directory in `DIRS` in the order listed; 2. the **app-directories loader**, trying `<app>/templates/` for each app in `INSTALLED_APPS`, in that order. The **first file found wins**. If no loader finds it, Django raises `TemplateDoesNotExist`; with `DEBUG` on, the error page includes a "template-loader postmortem" listing every path tried, which is the fastest way to debug a wrong location. If several engines are configured, `get_template()` tries each engine in order until one succeeds. ## Overriding templates from other apps The search order is how you customize templates you don't own: - A file in a `DIRS` folder beats every app template of the same name, so `templates/admin/base_site.html` at project level overrides the admin's version regardless of app order. - Between apps, **`INSTALLED_APPS` order decides**: an app listed before `django.contrib.admin` can override admin templates from its own `templates/admin/` folder; listed after, its copy is ignored. ## Namespacing app templates All app `templates/` folders are merged into one search space, so two apps both shipping `templates/detail.html` collide and the first app in `INSTALLED_APPS` silently wins. The convention is a subdirectory named after the app: - `stores/templates/stores/detail.html`, loaded as `"stores/detail.html"`; - `catalog/templates/catalog/detail.html`, loaded as `"catalog/detail.html"`. The duplicated folder name looks redundant, but it is what keeps names unique. ## Where to put which template - **Project-wide layouts** (`base.html`, error pages, overrides of third-party templates): a `DIRS` folder such as `BASE_DIR / "templates"`. - **App-owned pages and fragments**: `<app>/templates/<app>/`, so the app stays reusable. - **Per-store or per-tenant overrides**: an extra `DIRS` entry listed earlier, since `DIRS` order is the search order. ## Common mistakes - Forgetting `APP_DIRS: True` and wondering why app templates are not found. - Relying on `INSTALLED_APPS` order to pick between two unnamespaced templates. - Setting both `APP_DIRS` and an explicit `OPTIONS["loaders"]` list, which Django rejects with `ImproperlyConfigured`.
- Your app ships templates/admin/base_site.html but the admin still shows its default header. Why?The app-directories loader searches apps in `INSTALLED_APPS` order and uses the first match, so if `django.contrib.admin` is listed before your app, the admin's own file wins. Move your app above the admin, or put the override in a `DIRS` folder, which the filesystem loader searches before any app.
- How do you see which paths Django tried when TemplateDoesNotExist is raised?With `DEBUG = True`, the error page includes a template-loader postmortem listing, for each engine and loader, every path it tried and why it failed. It shows immediately whether the file is in the wrong folder, missing the app-name subdirectory or hidden by `APP_DIRS` being off.
saying these in an interview costs you the question
- Django searches app templates before the DIRS folders.
- APP_DIRS defaults to True in Django's settings.
- Each app's templates are isolated, so same-named files never collide.
- INSTALLED_APPS order has no effect on which template is used.
- If two templates match, Django merges or reports the conflict.