How to Add a Favicon in Django
Add a favicon to a Django project step by step: prepare the logo artwork, place the files in static, link them in your base template, handle /favicon.ico, and verify the result.
Contents
- Key terms
- Step 1: Choose the symbol and prepare the artwork
- Step 2: Export the favicon files
- Step 3: Place the files in Django static files
- Step 4: Link the favicon in your base template
- Step 5 (optional): Serve /favicon.ico at the site root
- Step 6: Deploy the static files
- Step 7: Verify the result
- Gaps to check yourself
To add a favicon in Django, put the icon file in your static files, load it in your base template with the {% static %} tag inside a <link rel="icon"> element, and optionally route the root /favicon.ico path to that file. A favicon is the small icon browsers show in tabs, bookmarks and history. The Django part takes a few minutes. Most of the real decisions are about the artwork: which part of the logo to use, which file formats to export, and how to check that the icon still reads at very small sizes.
Key terms
- Vector artwork: a logo defined by mathematical paths (lines and curves) instead of pixels, so it can be scaled without losing sharpness. SVG is the common vector format on the web.
- Raster image: an image made of a fixed grid of pixels, such as PNG. Each raster export has one fixed size.
- ICO: a container format that can hold several raster images of different sizes in one file. Browsers have long recognized it for favicons.
- Static files: in Django, assets such as CSS, JavaScript and images that are served as-is rather than generated per request.
Step 1: Choose the symbol and prepare the artwork
A full logo with a wordmark rarely works as a favicon because the text becomes unreadable at tab size. Start from your vector master file and pick the simplest recognizable element: a standalone symbol, a monogram, or a single initial from the logo. This is a design recommendation, not a technical requirement, but it is the decision that most affects whether the icon is useful.
- Remove fine details, thin strokes and small counters (enclosed spaces inside letters) that will blur or fill in when scaled down.
- Use a square artboard and center the symbol with balanced padding so it does not look cropped or tiny in the tab.
- Check contrast against both light and dark browser themes. A transparent background with a dark mark can disappear on a dark tab bar.
- Keep the vector source as the master. Export raster and ICO files from it rather than scaling up an existing small image.
- Preview the result at actual size on screen, not only zoomed in inside your design software.
Two cautions about source files. A file named .svg is not proof that it contains clean vector paths: an SVG can wrap an embedded raster image, which gives you none of the scaling benefits. Open it in a vector editor and inspect the paths. Also, having a logo file does not mean you have permission to use it. Confirm that you own the mark or are licensed to use it on the site.
Step 2: Export the favicon files
A practical baseline is a favicon.ico for broad compatibility, plus optionally an SVG version for browsers that support SVG favicons and a PNG for platforms that use their own icon conventions, such as home-screen shortcuts on mobile devices. The exact pixel sizes each browser or platform expects are not covered by the evidence for this guide. Check current browser and platform documentation before finalizing exports instead of relying on a fixed list.
If you export an SVG favicon, keep it simple and self-contained. Remove editor metadata, unused definitions and references to external fonts. Convert any text to outlines so the icon does not depend on fonts being installed.
Step 3: Place the files in Django static files
Put the files in a static directory that Django's staticfiles app can find, either inside an app or in a project-level folder listed in STATICFILES_DIRS. Make sure django.contrib.staticfiles is in INSTALLED_APPS and that STATIC_URL is set.
# settings.py
INSTALLED_APPS = [
# ...
"django.contrib.staticfiles",
]
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATIC_ROOT = BASE_DIR / "staticfiles" # used by collectstatic in production
project_root/
static/
favicon.ico
favicon.svg
apple-touch-icon.png
Step 4: Link the favicon in your base template
Add the link elements to the <head> of the base template that your other templates extend, so every page gets the icon. The {% static %} tag builds the correct URL from STATIC_URL, including hashed filenames if you use manifest-based static storage.
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="icon" href="{% static 'favicon.ico' %}" sizes="any">
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{% static 'apple-touch-icon.png' %}">
<title>{% block title %}My site{% endblock %}</title>
</head>
If you only have an ICO file, the first link line is enough. Browsers that support SVG favicons can use the SVG entry. Others fall back to the ICO.
Step 5 (optional): Serve /favicon.ico at the site root
Some browsers and tools request /favicon.ico directly, regardless of what the HTML says. Pages without your base template, such as some error pages or raw file responses, also lack the link tag. Without a route, those requests return 404 errors. One common approach is a redirect in the root URL configuration:
# urls.py
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import path
from django.views.generic.base import RedirectView
urlpatterns = [
path(
"favicon.ico",
RedirectView.as_view(url=staticfiles_storage.url("favicon.ico")),
),
# ... your other routes
]
If you use manifest-based static storage, staticfiles_storage.url() at import time needs the manifest to exist, so run collectstatic before starting the app in that setup. Alternatively, have your web server map /favicon.ico directly to the collected file.
Step 6: Deploy the static files
In development, the runserver command serves static files automatically when DEBUG is on. In production, Django does not serve them by default. Run collectstatic to copy the files into STATIC_ROOT, then serve that directory with your web server, a CDN, or a package such as WhiteNoise.
python manage.py collectstatic
Step 7: Verify the result
- Open the static URL of the icon directly in the browser (for example, the path under STATIC_URL) and confirm the file loads instead of returning 404.
- Load a page and inspect the <head> in developer tools to confirm the link tags render with the expected URLs.
- Check the Network panel for the favicon request and its status code.
- If you added the root route, request /favicon.ico and confirm it redirects to the static file.
- Browsers cache favicons aggressively. If the old icon or no icon still appears, try a private window, a different browser, or clearing the cache before assuming the setup is wrong.
- Look at the icon in a real tab, in both light and dark themes, to confirm the symbol is legible at actual size.
Gaps to check yourself
The evidence available for this guide does not include specific browser support tables or required pixel dimensions for each platform's icons. Those details change over time. Confirm them against current browser and platform documentation, and against the Django documentation for the version you run, before treating any export list as final.