skip to content

Why does the order of INSTALLED_APPS matter in Django when two apps provide a template, static file or management command with the same name?

level: middleimportance: should knowfreq 42%

answer

  1. several apps, one resource name
  2. first listed wins
  3. overriding the admin's templates
  4. project DIRS searched before apps

basics

~20 s

When several installed apps provide the same template, static file, management command or translation, the app listed first in INSTALLED_APPS takes precedence. To override django.contrib.admin's template from your own app, your app must come before the admin in the list.

solid answer

~40 s

Django's settings reference states the rule: when several applications provide different versions of the same resource — template, static file, management command, translation — the application listed first in `INSTALLED_APPS` has precedence. So a `branding` app that ships `templates/admin/base_site.html` only overrides the admin's version if it is listed **before** `django.contrib.admin`. The same first-wins rule decides which `static/css/site.css` `collectstatic` copies and which app's `send_reminders` command runs. One qualifier: with the default loaders, template directories in `TEMPLATES['DIRS']` are searched before any app, and `STATICFILES_DIRS` before app `static/` folders, so project-level overrides win regardless of app order. Order also sets the sequence in which apps are loaded and their `ready()` methods run.

go deeper

for a junior

Remember that the first app listed in INSTALLED_APPS wins when two apps provide the same template, static file or command.

for a middle

Walk through the admin base_site.html override and explain why project DIRS and STATICFILES_DIRS beat app directories under the default loaders and finders.

for a senior

Debug silent shadowing between third-party and local apps with findstatic and template namespacing, and document ordering constraints in settings.

for a principal

Decide whether site-wide overrides live in project directories or a dedicated app, so ordering is explicit and survives new apps being added.

## The rule Django's settings reference is explicit: "When several applications provide different versions of the same resource (template, static file, management command, translation), the application listed first in `INSTALLED_APPS` has precedence." In other words, the search walks the apps **top to bottom and stops at the first match**. ## Where the rule shows up | Resource | Who searches the apps | Consequence of order | |---|---|---| | templates | the app-directories template loader | the first app with `templates/<name>` supplies it | | static files | the app-directories static finder used by `collectstatic` | the first app with `static/<path>` is copied | | management commands | `get_commands()` | the first app defining `<name>.py` in `management/commands/` wins | | translations | the translation machinery | catalogs from earlier apps take precedence | | `ready()` and loading | the app registry | apps load and run `ready()` in list order | ## The classic example: overriding the admin On a clinic-booking site you want the admin header to say "Clinic Admin". You add a `branding` app with `branding/templates/admin/base_site.html`. The template reference spells out the trap: your app "must come *before* `django.contrib.admin`" or "`django.contrib.admin`'s will be loaded first and yours will be ignored". ```python INSTALLED_APPS = [ "branding", # listed first: its admin/base_site.html wins "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "scheduling", "patients", ] ``` ## The qualifier: project directories come first App order only decides between **apps**. With the default configuration: - the filesystem template loader (reading `TEMPLATES['DIRS']`) is tried **before** the app-directories loader, so a template in a project-level `templates/` directory beats every app; - `STATICFILES_FINDERS` lists the filesystem finder (reading `STATICFILES_DIRS`) **before** the app-directories finder. That is why many teams put site-wide overrides in a project `templates/` directory instead of relying on app order. ## Why this bites in practice 1. **Silent shadowing.** Two apps each ship `templates/base.html`; one wins and the other's pages look wrong with no error. Namespacing templates as `templates/<app_label>/...` avoids accidental collisions. 2. **Third-party overrides.** A package that restyles the admin must be listed above `django.contrib.admin`, and its install docs usually say so. 3. **Command clashes.** Two apps defining `import_data` means only the earlier one's command is reachable by that name. 4. **Static collisions.** `collectstatic` keeps the first file found for a path; `findstatic <path>` lists every candidate location to show which one won. ## A debugging walk-through Suppose the clinic's admin still shows the stock "Django administration" header after you add the override: 1. Confirm the file path is exactly `branding/templates/admin/base_site.html` and that `APP_DIRS` is enabled, so app template directories are searched at all. 2. Check `INSTALLED_APPS`: `"branding"` must appear above `"django.contrib.admin"`. 3. Check `TEMPLATES['DIRS']`: a project-level `admin/base_site.html` there would beat both apps. 4. Restart the development server if the cached template loader kept an old lookup. For static files the equivalent check is `findstatic`, which prints every candidate location in search order. For commands, `python manage.py help` lists commands grouped by the app that provides them, which shows which app's version is live. ## What an interviewer is listening for A middle candidate states "first listed wins" and gives the admin-template example. A stronger one adds that project `DIRS` and `STATICFILES_DIRS` beat all apps by default, recommends namespacing to avoid accidental shadowing, and knows `findstatic` for debugging which file won.

  • How do you see which app's static file collectstatic will pick?
    Run `python manage.py findstatic css/site.css`. It lists every matching location the finders see, in search order; the first one listed is what `collectstatic` copies. `findstatic --first` prints only that winning path.
  • Why namespace an app's templates under templates/<app_label>/?
    All app template directories share one search space, so two apps shipping `templates/detail.html` collide and the first listed app silently wins. Putting them under `templates/scheduling/detail.html` makes the name unique, so order only matters when you deliberately override another app's template.

saying these in an interview costs you the question

  • Says the last app in INSTALLED_APPS overrides earlier ones
  • Believes INSTALLED_APPS order never affects behaviour
  • Expects Django to raise an error on duplicate template names
  • Thinks app order beats templates in TEMPLATES DIRS by default
  • Puts an admin-override app after django.contrib.admin