I’ve been loitering in #django on Freenode recently, and misunderstandings about static files have cropped up enough that I figure me putting this together might help.
A typical Django project will have multiple sets of static files. The two common sources are applications with a
static directory for media specific to them, and a similarly-named directory somewhere in the project for media tying the whole project together.
Ultimately, you want these all to end up in one place, to be served to the end user. This is where the
collectstatic command comes in; as the name suggests, it’ll collect all your static files together into that one place. Of course, if you have
DEBUG set to
True in your settings,
runserver will happily handle all this for you, but that won’t be the case for your final deployment (and nor should it be!)
So how does this all happen?
First of all, where to find the static files?
settings.py will be created with a
STATICFILES_FINDERS setting, with a value of:
These will be used to find the source static files. The
AppDirectoriesFinder is responsible for picking up
FileSystemFinder uses the directories specified in the
You’ll probably want
STATICFILES_DIRS to look something like the below:
1 2 3 4 5
STATICFILES_STORAGE setting controls how the files are aggregated together. The default value is
django.contrib.staticfiles.storage.StaticFilesStorage which will copy the collected files to the directory specified by
Do not confuse
STATIC_ROOT, to where static files are collected, with the aforementioned
STATICFILES_DIRS; the former is output, the latter are inputs. They should not overlap. This is a common mistake.
Update: To be absolutely clear,
STATIC_ROOT should live outside of your Django project – it’s the directory to where your static files are collected, for use by a local webserver or similar; Django’s involvement with that directory should end once your static files have been collected there
Last but not least,
STATIC_URL should be the URL at which a user / client / browser can reach the static files that have been aggregated by
If you’re using the default
StaticFilesStorage, then this will be the location of where your
nginx (or similar) instance is serving up
STATIC_ROOT, e.g. the default
/static/, or, better, something like
http://static.example.com/. If you’re using Amazon S3 this will be
http://your_s3_bucket.s3.amazonaws.com/. Essentially, this is wholly dependent on whatever technique you’re using to host your static files. It’s a URL, and not a file path
- Overlap between
STATIC_ROOT– the former is a set of places to look for static files, the latter is where they’re stored
STATIC_URL– it’s a URL, not a file path
- Incorrect configuration of whatever you’re using to host your static content; this is why I use S3, in my experience it’s the least effort to get working
STATIC_ROOTinside your project directory. While not strictly a mistake, it’s not where it belongs, and is generally a sign of other misunderstandings
All of these will assume you’ve left
STATICFILES_FINDERS as its default, and
STATICFILES_DIRS as described above; I’ve never yet had a reason, across dozens of projects, for these not to be the case
Apache serving static files
Apache config (e.g.
1 2 3 4
(Update: If you want more information on this topic, check out my follow-up blog post, Using Amazon S3 to host your Django Static Files)
Note this uses
django-storages, which is a nice wide-ranging collection of custom backends for
STATICFILES_STORAGE described above.
1 2 3 4
I frequently deploy to Heroku where custom httpd configuration is nontrivial, so often use this method.
Static file handling is important to get right, and straight forward once you know how, but easy to get wrong. I hope this clarifies things.
As ever, drop me a line if you have any queries, questions or complaints.