Even a fairly light-weight page will probably load some CSS and JS, and a few images - it’s pretty easy to find each page load triggering at least a dozen subsequent fetches. Now this doesn’t mean the files will be re-fetched - a sensible webserver setup will respond with 304 (Not Modified) and no content, so the browser will use its cache, but those are requests that don’t need to be made, and only so many that your server will handle at once.

Where static files are concerned, caching is simple: all you need are three easy things:

Set expiry headers Use CachedStaticFilesStorage Set Cache-Control: public

Set expiry headers

There are two important HTTP headers here: Expires and Cache-Control: max-age . They have slightly different semantics, but the distinction is minor - Apache and nginx both provide a single configuration directive to set both. They tell caches how long they can keep files for - you’ll want to set this to a year from access. Why a year? Historically this used to be the maximum allowed value - that restriction has been lifted, but in many cases, there’s little point in setting a larger value, and I don’t consider it worth it.

For Apache, this means first ensuring that mod_expires is enabled:

$ sudo a2enmod expires

then, in the configuration block serving your static files:

ExpiresActive on ExpiresDefault “access plus 1 year”

For nginx it’s much simpler (nearly all distros package nginx with the ngx_http_headers_module included):

expires 1y;

That’s it; now caches should keep your files for a year. Now you’re probably thinking that that’s fine for things that don’t change often, if at all, like images, but what about your CSS and JavaScript that tend to change between releases? This is where the next task comes in:

Use CachedStaticFilesStorage

STATICFILES_STORAGE = ‘django.contrib.staticfiles.storage.CachedStaticFilesStorage’

This is a slightly misleadingly-named class: what it does is rename your static files to include a hash of their content. If the content changes, the filename changes, so clients will get changes immediately rather than waiting for cached content to expire.

The “Cached” part of the name is because it uses the Django cache framework to store the hashes - Django 1.7 brings ManifestStaticFilesStorage which instead writes them to a JSON file it loads at startup - a much-awaited improvement!

There are two types of caches: private (e.g. a user’s browser) and public (e.g. an institutional shared proxy, or a local CDN).

Sending Cache-Control: public with your static files tells shared caches that it’s ok to retain them.

For Apache, this means ensuring that mod_headers is enabled:

$ sudo a2enmod headers

then adding the following to the configuration block for your static files:

Header append Cache-Control public

( append rather than set so as not to overwrite the Cache-Control: max-age setting described above; add would be equally valid)

For nginx:

add_header Cache-Control public

Conclusion

Caching configuration is really useful, and simple to set up. If you’ve not done it yet for your apps, follow this guide and speed things up for your users.