Django Favicon Generator
Django does not special-case favicons. Icons are ordinary static files collected into STATIC_ROOT and referenced from your base template with the static template tag. In production the collectstatic step is what makes them reachable.
Static files, not media
Favicons belong with CSS and JS under the static files system, not under MEDIA_ROOT. MEDIA_ROOT is for user uploads. Icons are part of the project, so they live in an app's static/ directory or in a project-level directory listed in STATICFILES_DIRS.
In development, django.contrib.staticfiles serves them automatically when DEBUG is True. In production you run collectstatic and let your web server or white-noise-style middleware serve STATIC_ROOT. Forgetting that step is why icons work locally and 404 after deploy.
Where the files go
- myproject/
- static/listed in STATICFILES_DIRS
- favicon.icoadd
- favicon-32x32.pngadd
- apple-touch-icon.pngadd180x180
- icon-192.pngadd
- icon-512.pngadd
- site.webmanifestadd
- templates/
- base.htmllink tags go here
- settings.py
- manage.py
An app-level path like blog/static/favicon.ico also works. Project-level static/ keeps site-wide icons out of any one app.
base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}My site{% endblock %}</title>
<link rel="icon" href="{% static 'favicon.ico' %}" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'favicon-32x32.png' %}">
<link rel="apple-touch-icon" href="{% static 'apple-touch-icon.png' %}">
<link rel="manifest" href="{% static 'site.webmanifest' %}">
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>Always use the static tag. A hardcoded /static/favicon.ico breaks when STATIC_URL changes or when ManifestStaticFilesStorage hashes the filename.
Settings that matter
| Setting | Role | Favicon impact |
|---|---|---|
| STATIC_URL | URL prefix for static files | Prefixed onto every {% static %} result |
| STATIC_ROOT | collectstatic output directory | Must be served in production |
| STATICFILES_DIRS | Extra project-level static dirs | Where a top-level static/ folder is registered |
| ManifestStaticFilesStorage | Content-hashes filenames | Requires {% static %}; breaks hardcoded paths |
Django favicon FAQ
Icons work in runserver but 404 in production.
collectstatic was not run, STATIC_ROOT is not being served, or WhiteNoise / your CDN is pointed at the wrong directory. Confirm the collected file exists under STATIC_ROOT and that the rendered HTML's href returns 200.
I enabled ManifestStaticFilesStorage and every icon broke.
Hardcoded /static/... paths no longer match the hashed filenames. Switch every href to {% static '...' %}, rerun collectstatic, and redeploy. The manifest mapping only works when the template tag asks for it.
Should the favicon live in an app's static/ folder?
Either works. App static folders are found automatically for installed apps; a project-level directory needs an entry in STATICFILES_DIRS. Prefer one project-level place for site-wide branding so you are not hunting through apps later.