Client Side Caching

CloundFront cache configuration for serverless deployment

Kelly Ripple
4 min readMay 17, 2019

Recently, we had a problem on the frontend where when we deployed new content to our S3 bucket, the changes would not be reflected in the browser. Our issue, as you will soon see, was a caching issue.

Caching is important because it makes your website faster. It decreases load time which in turn creates a better user experience. Referencing the image above, if a user navigates to a page they’ve previously viewed, the browser will immediately return a saved copy instead of retrieving the information from the internet.

Our app is an Angular application served via S3 and CloudFront, so there are actually two places to cache things: in the browser and in CloudFront.

Our problem was that, by default, CloudFront caches resources for one day. We weren’t seeing newly deployed webpages, we were seeing older cached versions.

Our first plan of attack was to manually invalidate the CloudFront cache for each new deployment. This solved the issue, but has the downside of being a manual process. As an alternative, we can use the Cache-Control HTTP header & content hashes

Content Hashes

One of the best (and easiest) ways of forcing the browser to retrieve new content exactly when it’s available is by busting the cache with content headers.

The premise is this: the way cache behavior works, resources are stored by path. If the path or filename changes, the browser treats it as a brand new file — which is exactly what we want it to do. We force this behavior by appending a content hash (usually an md5sum) to the filename and updating all references to that file with the new name. Any unique identifier will work, but an md5sum is a good choice because even small changes to a file will cause the MD5 hash to change. Unchanged files will have the same hash, letting the cache do what it does best — reduce load time.

There are plenty of build tools that will do the work of appending to filenames and updating references for you. Angular specifically comes prepackaged with this functionality, all you need to do is set "outputHashing" to "all"in the angular.json configuration file.

This strategy works for basically everything except the index.html file, but I’ll get to that a bit later.

Cache-Control HTTP Headers

Cache-control headers are used to specify caching behaviors in HTTP requests and responses. In general, they inform the browser how long you want a particular item to be cached.

The traditional method of setting cache control headers is in a server. With a serverless configuration, we have two good options still available to us. Two good ways to configure cache-control headers on your entire distribution are by updating S3 metadata or by configuring CloudFront behaviors. CloudFront supports path matching which means you can configure different cache behaviors for different kinds of files, so that’s what we used.

For our hashed files, we want to set cache control headers to cache these files for as long as possible. We don’t need to worry about stale content because new deployments won’t contain any references to old files.

We created a default cache behavior in CloudFront that caches files for one year.

The index.html file is trickier to deal with. It’s inadvisable to rename it as there are often external dependencies that depend on or expect this naming convention. It is a small enough file, however, that we can get away with caching it for much less time than the CloudFront default of 24 hours. Our team went with 30 seconds, but there are some cases where you would want to cache the index for even less time.

With CloudFront path matching, we were able to create a behavior for the index.html file specifically, without worrying about affecting our other cache settings.

With a combination of CloudFront behaviors and build processing tools, we were able to solve our caching issue with a solution that works for all future deployments — no manual changes required.

--

--