Effective Browser Cache Control for Your Web Applications

Understanding browser cache control is essential for maximizing your website’s performance and delivering the best possible experience to your users. Have you ever gotten a Slack message from your QA Engineer telling you that the new feature that you just deployed to the QA environment is not working properly? And you respond back with “Did you clear your cache? Have you tried it in an incognito window?” Sure enough, they try your suggestions and the web app comes back to life and we go back to our business. But, what’s going to happen when your end-user gets that new release? Will they know to do a hard-refresh? Will they know to clear our their browser history and start over? In this episode, let’s look at a few things that you can do, to make your website running smoothly, from one deployment to the next.

What is Browser Cache Control?

Browser cache control is the process of controlling how web content is stored and retrieved by a user’s browser. By properly setting cache headers and handling cache invalidation, you can ensure that your website’s content is cached efficiently, reducing load times and improving the user experience. When a user visits a website, the browser will store certain files, such as images and scripts, in a temporary storage location called the cache. This allows the browser to quickly retrieve those files on subsequent visits to the website, rather than having to download them again. However, the cached content can become stale or outdated over time and your application must be smart enough to have the browser reach back up to your server to fetch the latest and most up-to-date version. This will require some preplanning on your part. If you set the cache for a long duration but then make an updated version of that resource, the browser will not bother checking for an updated version, until that cache expires. Below, I’ll provide some general guidance on setting cache parameters for your various static and dynamic resources and some other practices that you can do in conjunction with this such that you can avoid a lot of common mishaps that arise for poor cache management.

Setting Cache Headers

browser tools showing the cache-control header and an expires header for an HTTP resource

One of the most effective ways to control how browsers cache your content is by setting cache headers. Cache headers are response headers that tell the browser how to cache a particular resource. The most common cache header is the cache-control header, which specifies the maximum amount of time that the browser should cache a resource before requesting a fresh copy from the server. For example, a cache-control header of “max-age=3600” would instruct the browser to cache the resource for 1 hour before re-requesting it. Or you can set that header’s value to “no cache” to instruct the browser that the associated resource must not be included in any caching. Other cache headers include the expires header, which specifies an absolute date and time after which the browser should re-validate the resource, and the etag header, which allows for conditional requests based on the content of the resource. You can learn more about the cache-control HTTP response header from MDN, here.

General Caching Guidance for Modern Web Apps

I’ll caveat this section by stating that this is some very general guidance. I do not know your personal situation and as such, your mileage may vary.

Uniquely named JS files, resulting from a Vue application build process.

If you’re building modern web apps with one of the popular Single Page Application (SPA) frontend frameworks such as Angular, React or Vue, the build process associated with these frameworks, out of the box, will give you your static resources – namely your JavaScript and CSS files, with unique names (usually with a hash of some sort included in the filename) so that every new build will produce files with names that you haven’t encountered before. Why is this relevant for caching? If your build process is generating a newly named file with every new build, you can rest assured that the browser has not encountered that filename before and as such, cannot retrieve that resource from its cache. The only place where it can acquire that resource is from your server.

index.html file from a Vue app.

But wait, how will the browser know to request that new resource if it hasn’t seen it? Those new resources – JavaScript and CSS files, mostly, are referenced in your index.html file, that singe page, in your single page application. However, if the browser is caching that index.html file, you’re doomed! The browser will happily use your outdated index.html file until the cache for it expires.

So here are a couple of key takeaways:

  • Do not let your browser cache your index.html file. In fact, you probably want to avoid caching any .html files if you are going to reference other JavaScript and/or CSS resources within them, that you may update at one point or another. If you disallow caching of these, the browser is then forced to go back to the server each time for it which may be a small price to pay if you want to ensure that it will then fetch the latest JS and CSS resources every time you push an update. As mentioned above, you can set a cache-control: no cache header on the response of these to instruct the browser not to cache it.
  • Then, in turn, you can probably set very long durations on the CSS and JS files that are linked in this HTML file because each of those will have new names whenever you conduct a new build.
  • What about API calls? It depends. If you can distinguish one user’s request from another, perhaps by a URL segment or a query string, and you can reasonably estimate the frequency at which that response payload changes, you may be able to set some caching to ease the server load. Otherwise, you’re probably better off setting these to either no cache or to a short duration. P.S. In this post, we’re concentrating on client (i.e., browser) caching. We can dig into server-side caching in a future episode where we look at how we can take advantage of caching on the server side, to ease burden or upstream resources such as database servers or third-party APIs.

Conclusion

Try to put an effective caching strategy in place before your application goes live. If your application is already live, prioritize this work so that you can correct any existing issues and put yourself in a position where further updates can be delivered effectively and efficiently to your customers. With the ever-increasing importance of website performance in today’s digital landscape, mastering browser cache control is a must for any developer looking to create fast, reliable, and engaging web applications.

Leave a Comment

Your email address will not be published. Required fields are marked *