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.
- 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.
- 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, like for a specific location or file type, within your server 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.
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 or have their own mechanism in place to imitate the immutable
functionality.
- Firefox - supported since Firefox 49.
- Microsoft Edge - supported since Edge 15.
- Chrome - Not supported. as Chrome already has a feature implemented that prevents subresource revalidation on reload.
- Safari - Supported in Safari Technology Preview 24.
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.