Static Files
Static files in Django are the unchanging assets your site serves alongside HTML — CSS stylesheets, JavaScript, images, and fonts — and the staticfiles app provides a consistent way to locate, reference, and collect them for production.
Learn Static Files in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll learn where static files live inside your apps, how to reference them in templates with the static tag, and how to gather them into one folder for deployment with collectstatic.
Static files are assets that never change per request — CSS, JavaScript, images, and fonts. Django's staticfiles app (already in INSTALLED_APPS by default) expects each app to keep its assets in a folder named static inside the app.
The convention is to add an extra namespacing folder with the app's name, so the path becomes blog/static/blog/ . This prevents two apps that both ship a style.css from overwriting each other when everything is collected together.
The STATIC_URL setting in settings.py defines the public URL prefix Django uses when it generates links to these files:
You should never hard-code /static/... URLs into your HTML. Instead, load Django's static template-tag library and use the {' '} tag, which builds the correct URL from STATIC_URL for you.
First, put {' '} at the very top of the template. Then call {' '} wherever you need a URL:
When Django renders this template, each static tag is replaced with a real URL — for example {' '} becomes /static/blog/css/style.css in the HTML the browser receives.
During development Django's server finds static files automatically, app by app. In production you want a single folder a fast web server can serve directly. That's what collectstatic builds.
You point STATIC_ROOT at the destination folder and, optionally, list extra project-wide asset folders in STATICFILES_DIRS :
Then run the command as part of every deployment:
Fill in the blank so the function returns the correct namespaced path for the blog app's stylesheet, matching what you'd pass to the static tag.
❌ TemplateSyntaxError: Invalid block tag 'static'
You used the static tag but forgot to load its library.
✅ Fix: add {' '} at the very top of the template before any static tag.
❌ 404 Not Found on a CSS or image in production
Your assets exist in apps but were never gathered into STATIC_ROOT.
✅ Fix: run python manage.py collectstatic on every deploy, and make sure your web server serves STATIC_ROOT.
The folder nesting is wrong — the file isn't under app/static/app/ .
✅ Fix: place assets in blog/static/blog/... and reference them as blog/... , not the bare filename.
Write a helper that builds the rendered HTML link tags for a list of an app's CSS files, exactly as the static tag would after rendering.
Lesson 5 complete — your assets are wired up!
You now know where static files live, how the static tag turns a namespaced path into a real URL, and how collectstatic, STATIC_ROOT, and STATICFILES_DIRS prepare your assets for production.
🚀 Up next: The Django Admin — explore the auto-generated admin site for managing your data.
Practice quiz
What does the STATIC_URL setting define?
- The filesystem folder collectstatic writes to
- Extra source folders to collect from
- The public URL prefix browsers use to request static files
- The default app for serving media uploads
Answer: The public URL prefix browsers use to request static files. STATIC_URL (e.g. 'static/') is the URL prefix Django uses when building links to static files.
Which app must be in INSTALLED_APPS to use Django's static files handling?
- django.contrib.staticfiles
- django.contrib.staticserve
- django.static.files
- django.contrib.assets
Answer: django.contrib.staticfiles. django.contrib.staticfiles is included by default and powers the staticfiles system.
What does the collectstatic command do?
- It minifies CSS and JavaScript automatically
- It copies every app's static files into the single STATIC_ROOT folder
- It deletes unused static files from your apps
- It uploads files directly to a CDN
Answer: It copies every app's static files into the single STATIC_ROOT folder. collectstatic gathers files from each app and STATICFILES_DIRS into STATIC_ROOT for production.
Which setting names the single destination folder collectstatic writes into?
- STATIC_URL
- STATICFILES_DIRS
- MEDIA_ROOT
- STATIC_ROOT
Answer: STATIC_ROOT. STATIC_ROOT is the filesystem path collectstatic copies all static files into.
What must appear at the top of a template before using the static tag?
- {% load static %}
- {% static load %}
- {% import static %}
- {% include static %}
Answer: {% load static %}. Adding {% load static %} imports the tag library so {% static %} is available in that template.
In a template, how do you build the URL for an asset named blog/css/style.css?
- {{ static 'blog/css/style.css' }}
- {% url 'blog/css/style.css' %}
- {% static 'blog/css/style.css' %}
- {% asset 'blog/css/style.css' %}
Answer: {% static 'blog/css/style.css' %}. The {% static 'path' %} tag turns a relative path into the full URL using STATIC_URL.
What is STATICFILES_DIRS used for?
- The destination collectstatic writes to
- Extra project-wide source folders to collect static files from
- The URL prefix for media uploads
- A list of apps allowed to serve static files
Answer: Extra project-wide source folders to collect static files from. STATICFILES_DIRS lists additional source folders, not tied to a single app, that collectstatic reads from.
Why is the extra app-name folder used, as in blog/static/blog/?
- It is required by Python's import system
- It enables automatic CSS minification
- It tells Django to compress the files
- It namespaces each app's assets so files with the same name do not collide
Answer: It namespaces each app's assets so files with the same name do not collide. The namespacing folder keeps two apps' identically named files separate once collected together.
If you forget {% load static %} but use {% static %}, what happens?
- The file is served from MEDIA_ROOT instead
- Django silently returns an empty string
- Django raises a TemplateSyntaxError about an invalid 'static' tag
- The tag works because static is built in
Answer: Django raises a TemplateSyntaxError about an invalid 'static' tag. Without loading the library, Django reports the static tag is invalid (TemplateSyntaxError).
STATICFILES_DIRS and STATIC_ROOT should never point at the same directory because:
- One is a source folder and the other is the destination collectstatic writes to
- STATIC_ROOT must always be empty
- Django only allows one static folder per project
- STATICFILES_DIRS must live inside an app
Answer: One is a source folder and the other is the destination collectstatic writes to. STATICFILES_DIRS lists sources Django reads; STATIC_ROOT is the destination it writes to, so they must differ.