Documentation

Cache-Busting

After deploying a new bundle, you might sometimes find that changes to some of your front-end assets haven't appeared. SSH-ing into your environment shows that the updated assets are deployed, but accessing them via your site's URL shows the old, stale content. Weird!

95% of the time this is down to caching from proxy services like Cloudflare or Cloudfront, who by default will perform dynamic caching policies to try and cache paths that don't often change. To get around this, "cache-busting" measures need to be introduced to the project so that changes appear immediately after a new bundles are deployed.

Using Query Parameters #

The easiest way to cache-bust is to add a unique query parameter to the asset's URL. This works because by default proxy services include query parameters in their cache keys, so changing the query parameters means they'll serve different cached content.

If the URL has been requested before with the query parameter, then it's possible you'll receive stale cached content, so make sure it definitely is unique and hasn't been requested before.

Example #

Say your asset exists at the following URL:

https://www.example.com/assets/main.css

You could cache-bust it by hardcoding a query parameter, like this:

https://www.example.com/assets/main.css?v=1

This is great, but what about the next time you push an update to asset? You'll need to update the v=1 parameter to something else, like v=2. That's a bit manual, and prone to being forgotten about, so lets see about improving it with a bit of automation.

Using The Bundle Hash #

Whenever a bundle is synced, Servd injects a SERVD_BUNDLE_HASH environment variable behind the scenes that Craft can access. The value of it is a unique hash of various aspects of the deployed bundle, e.g. the git commit hash, PHP version, etc.

This is pretty handy as we can use it as part of a cache-busting query parameter. Adding it to URLs in our twig templates might look something like this:

https://www.example.com/assets/main.css?v={{ getenv('SERVD_BUNDLE_HASH') }}

Much better! Not only is this an automated approach that we can just forget about, it has the nice advantage that if we want to roll back to the previous bundle, the old version of the asset will already be cached by the proxy service.

Using Filenames ⚠️ #

Adding random hashes to asset filenames for the purposes of cache-busting is an alternative to query parameters that some front-end tools employ, e.g.

https://www.example.com/assets/main.aj43kj4.css

However if your asset is included in your bundle, as is common with Servd projects using our Node Build Step, we don't recommend using this method.

If a page is statically cached (e.g. via Servd's static caching), then it will have a URL with a random hash baked into the HTML, e.g /assets/main.a1b2c3.css. When a new bundle is deployed, whose asset is now at /assets/main.d4e5f6.css, the cached HTML will still point to /assets/main.a1b2c3.css, which will now return a 404 response. 😣

A common symptom of this issue is unstyled content being rendered whenever a new bundle is deployed, which is resolved by clearing the static cache.

If you'd like to continue using filename-based cache-busting vs. query parameter based caching, then you might want to consider doing one of the following:

  • Clear your static cache as part of your Post-Deploy Tasks.
  • Include historical copies of your asset in the bundle so that stale statically cached pages can successfully load the asset.