Improving Performance with Cache-Control: Immutable

By Cody Arsenault
Updated on May 12, 2017
Improving Performance with Cache-Control: Immutable

Cache-Control is an important HTTP header that allows you to define various directives letting browsers know how an asset should be cached. For example, if an asset has a large max-age, then the asset can be retrieved from the browser for a long period of time without making a request to the server. This means faster load times for the user.

We’ve covered many of the popular directives you can define for the Cache-Control header, however, in this post we’re going to cover a Cache-Control extension called: immutable to see what kind of impact it can have on performance.

What Is Cache-Control: Immutable?

The cache-control: immutable directive was first introduced in Firefox 49 to provide the browser with hints as to which resources never change. Why introduce this directive you might ask? Well, let’s say you have a page that loads static content which likely won’t change for extended periods of time (e.g. images, JavaScript, CSS files, etc). Upon each reload, the browser needs to check the server to see whether those assets need to be revalidated thus slowing down performance.

Of course, these assets will return a 304 Not Modified HTTPS status instead of a 200 status, as long as they are unchanged, however, the revalidation process still takes time and uses bandwidth.

In fact, for smaller assets, going through the server-side validation process can often take just as long as transferring the complete asset itself. Therefore, for certain assets which you are confident do not require conditional revalidation (If-None-Match or If Modified Since), it can be beneficial to mark them as immutable.

Benefits of Immutable

In terms of the benefits of using the immutable directive, there are two major advantages.

  1. Better performance for the user - Since the browser doesn’t need to check the server to verify whether or not the asset is still valid, the static assets can be delivered faster from the browser cache.
  2. Less bandwidth usage - Since the browser doesn’t need to check with the server regarding whether or not the asset is still valid, this means less network bandwidth is consumed.

Facebook was amongst the first to adopt the immutable directive. The concern of decreased performance due to conditional revalidation was a major issue for them as with a social network like Facebook, users are refreshing the page quite often to see the latest updates. Since the page is being constantly refreshed and although many static assets return a 304 (about 20% of their assets), the browser still needed to check the server-side to verify whether or not the assets changed since the last time they were accessed.

However, since implementing the immutable directive, Facebook was able to prevent the browser from constantly checking the server thus improving performance and decreasing bandwidth usage.

Immutable Caching Example

The immutable directive is quite simple to implement. Like other Cache-Control directives, it just needs to be defined within the Cache-Control HTTP response header for a specific location, file type, etc within your server’s configuration file. Since immutable is complemented by the lifetime expiry value expressed by max-age (or a similar directive), here is an example of what your Cache-Control header might look:

cache-control: public,max-age=31536000,immutable

In Facebook’s case, you can clearly see this directive added to their subresources by running a simple cURL command:

curl -I https://www.facebook.com/rsrc.php/v3/yz/l/0,cross/CNEKuXia69g.css
HTTP/1.1 200 OK
timing-allow-origin: *
X-XSS-Protection: 0
Content-Type: text/css; charset=utf-8
X-Content-Type-Options: nosniff
Access-Control-Allow-Credentials: true
Cache-Control: public,max-age=31536000,**immutable**
Expires: Sun, 22 Apr 2018 05:32:27 GMT
Content-MD5: adbMXOEXPhg4r8SRH5i4xA==
Last-Modified: Mon, 01 Jan 2001 08:00:00 GMT
Access-Control-Allow-Origin: *
Vary: Accept-Encoding
X-FB-Debug: MyS/UcBBoxW1ZwRmkM3NeNCIFgI4EFI2Yqbw/AUEktYczR2H8FGkVS+M8fxLr8MKcuKp3PVN8g0aRMt9H8usCQ==
Date: Sat, 22 Apr 2017 05:32:27 GMT
Connection: keep-alive
Content-Length: 682

Additionally, by checking the Network tab in Firefox’s developer tools, we can clearly see that although the page is refreshed multiple times, the status remains 200 instead of 304. Although, if we look under the Transfer tab, we can see that each subresource asset is coming from cache instead of the server.

facebook cache control immutable

Cache-Control: Immutable Configuration

The immutable directive configuration process requires only a slight addition from what you would use to add Cache-Control headers to your assets. The following two examples show how you can implement the Cache-Control: Immutable directive in either Apache or Nginx.

Apache

The following snippet can be added to your .htaccess file or Apache configuration file to tell the server to set the Cache-Control header’s max-age to 31536000 seconds, as well as the directives “public” and “immutable” for the listed file extensions.

<filesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
    Header set Cache-Control "public, max-age=31536000, immutable"
</filesMatch>

Nginx

This snippet can be added to your Nginx configuration file. The example below uses the same Cache-Control directives and values as the Apache example above.

location ~* \.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

Browser Support

As for browser support, the immutable directive isn’t universal just yet. The list below outlines which browsers support immutable and which ones either don’t support it / have their own mechanism in place to imitate the immutable functionality.

It should also be noted that Firefox only honors the immutable directive over HTTPS. All browsers that do not support the immutable directive simply ignore it, therefore it is safe to add and won’t cause any conflicts.

Summary

If you have static assets that you know aren’t going to change for an extended period of time it may be worthwhile adding the immutable directive to your Cache-Control response header. This is especially useful for webpages or application that users need to reload often as it nullifies the need for browsers to perform conditional revalidation. Therefore ultimately, improving overall performance and reducing bandwidth consumption.

Leave a comment