- Increase your asset cache lifetime
- A million files
- Cache-Control header
- Implementing Cache-Control for static assets
Increase your asset cache lifetime
Between these changes, however, sprite images, CSS files and JS files are static - and you should have your users get them only once! First time visitors have to download these files initially and will hence not profit. But the bunch of visitors returning to your site will be pleased to have all assets load instantly, leading to a much improved browsing experience.
“But”, I hear you say, “if my assets live forever, how can I make sure visitors see the newest styles and images?” There’s at least one way to ensure this, and we’ll walk through it in this post.
Moreover I’ll show you how to set appropriate caching headers so your visitors’ browser will know how to deal with your assets.
If you haven’t done any fancy cache-busting magic on your site, it probably has some asset files like this:
screen.css as an example, although it applies to
scripts.js (and it’s equivalent in your project) in a similar fashion. As you develop your site, you make a lot of changes to
screen.css, deploying different versions of it over time.
To ensure your users are downloading the current version of your
screen.css, you could be using a “hack” like appending the version code when referencing your stylesheet:
While it fulfills the purpose of having visitors download the current version of your assets, it largely disallows caching in browsers.
A great way to deal of combining both is to embed any version identifier into the filename:
Now, instead of updating your version parameter, you’d have to update the actual filename. While this would work, there is a way I personally prefer: Include a hash representing the file contents into the asset filename.
Alright, nobody would ever generate these filenames by hand, so you’ll better let your asset pipeline tool of choice do the job. If you are using Compass you find a step by step guide for doing this here (Compass does this automatically for sprite images, but not for generated CSS).
A million files
Using version-tagged asset files will leave you with a lot of versions for each asset on your hard drive. You may want to clean them up.
When you can get rid of old asset file version largely depends on if any visitor could get a version of your site where this particular asset version is referenced.
If you have absolutely no HTML caching mechanisms in place, you have to keep the latest version of each asset only.
If you have HTML caching mechanisms, these will likely result in delivery of multiple asset versions in parallel. Therefore the highest cache lifetime determins the time you should keep your old asset versions available.
This is a great task for automation. If you followed my compass cache busting guide, you’ll have it in the pipeline already for your CSS.
At this point, your site has perfectly versioned asset files. As each version represents one state of your app, and new states will be referenced by new filenames, you can allow that these assets be cached for a looooong time.
I’d say a year is a good fit. What this means is that your visitors returning to your site have to only download asset files
- if you modify assets and your site embeds new versions
- if they clear their browser cache (or use a different browser, of course)
- if they revisit after more than a year
There’s a magic bullet for defining asset lifetime, the
Cache-control response header.
It’s syntax for lifetime is pretty simple:
A visitor’s browser is able to cache a request response sending this header for one hour (3600 seconds).
The official specification of Cache-Control shows several additional parameters available to control cache responses. Two are especially interesting, namely
Indicates that the response MAY be cached by any cache, even if it would normally be non-cacheable or cacheable only within a non- shared cache.
Because a cache MAY be configured to ignore a server’s specified expiration time, and because a client request MAY include a max- stale directive (which has a similar effect), the protocol also includes a mechanism for the origin server to require revalidation of a cache entry on any subsequent use. When the must-revalidate directive is present in a response received by a cache, that cache MUST NOT use the entry after it becomes stale to respond to a subsequent request without first revalidating it with the origin server. (I.e., the cache MUST do an end-to-end revalidation every time, if, based solely on the origin server’s Expires or max-age value, the cached response is stale.) […]
With these two options you basically allow intermediate caches (i.e. a CDN provider) to cache your assets as well for the specified time.
Combining these with a year-long lifetime, your assets should respond with the following Cache-Control header to be cached for one year:
Cache-control: max-age=1314000, public, must-revalidate
Setting this most likely requires access to your web server configuration, or at least an appropriately configurable
.htaccess file if you’re running your site on Apache.
Implementing Cache-Control for static assets
The following samples for the major three web servers assure that your Compass-generated static assets have a one year long lifetime.
If you are not using Compass or want to extend these rules to include other assets, you’ll have to change the relevant matching rules.
Cache-Control header for Apache
There are two ways to trigger cache control in Apache.
If it is available on your server,
mod_expires provides a easy to configure way to set asset lifetime.
.htaccess file in your
assets directory and your Apache webserver will start delivering all assets within with appropriate headers.
Again, placed in the
assets directory this marks all responses to be cachable for one year.
Cache-Control header for nginx
Warning: The following configuration is untested.
It should, however, set the lifetime to sometime in 2037 for all files in
assets/. Check the [nginx-expires][documentation] and these configuration examples for details.
Cache-Control header for lighttpd
Option 1: Using mod_expire
Option 2: Using mod_setenv
Assets are requested only at first visit, and then cached. Returning visitors will have all your assets readily available without downloading again.