Using asset immutability to improve performance

25 Nov 2018

Every website has assets. You may or may not call them by that name, but every image, video, CSS file or JavaScript include is an asset that needs to be downloaded and interpreted by the user’s browser.

In order to improve performance by not downloading the same files every time they are requested, nearly every browser implements some kind of cache. This also helps save bandwidth for both the user and the operator of the website.

Nevertheless, all files need to be downloaded at least once, and then again when the cache expires, so there are still plenty of opportunities to optimise your users’ experience.

Cache invalidation

One of the two most difficult things in computing (alongside naming things and off-by-one errors) is cache invalidation - that is, the art of caching things just as long as required to prevent useless queries, without caching it for too long and preventing updates from showing up in a timely fashion.

Cache invalidation is an ongoing concern, and it is very easy to fall into one of its traps, such as updating a file without renaming it, thereby meaning users continue to see the old file for a variable amount of time until their browser decides its time to ask for the latest version of it.

How a lot of people handle this issue

For many years, one of the most popular ways of ensuring that updated files are served immediately to all users has been to manipulate the file name in some way so as to not make it match the previous version of the file that may have been cached by browsers.

A lot of web frameworks now support this by default, calling it something akin to asset hashing or similar.

This means that given a file of logo.png, the framework will output a file named something like logo-2c33f58a-134a-4faf-b66b-1903354f21b3.png. In this case, a UUID has been appended, but it may also be a hash of the contents of the file, which has the added advantage that rebuilding assets will not rename ones that have not changed. Alternatively, some frameworks will append a query string to the file name, again with a UUID, hash, or maybe the last changed date of the file.

How unique file names help

When we look at the various schemes used by frameworks to guarantee immediate serving of the latest contents of files, a thought may pop up - since the file name changes every time the contents change, that effectively means that a file with that unique file name will never change.

Carrying on with that thread, this means we can now tell browsers that they can cache such files forever (realistically, until they run out of space or the user manually clears their cache). Since any changes to the file will result in a new file name, we don’t need to worry about the old versions of files hanging around forever and users not being able to see our latest changes.

Assets can be immutable

The HTTP Cache-Control header, normally used to mark files as not being cacheable, or only to be cached for a limited time, now also supports marking files as immutable - that is, telling the browser that this file will never change and therefore don’t ever retry in case there’s a newer version.

This feature is, as of writing, supported by the Edge, Firefox and Safari browsers.

Usage is simple: just return the Cache-Control: immutable header along any files that will never change. The browser will the cache these files indefinitely and will never check for updates as long as the file remains in its cache.

This header can save a lot of wasted bandwidth for high-traffic sites. Even if your caching is configured correctly and your web server returns 304 Not Modified responses for unchanged files, these requests still take up time and bandwidth that is in effect wasted.

By using immutability, you can save time for users since the pages they request will load faster, and you can save bandwidth for your site from all the potential requests that have not been made.