by Valentin, March 25 2018, in tech

Do not use query string parameters for cache busting

When you want to refresh some static resource that might have been cached by caches you don't have control over, you have to change the URL of the resource so that those caches won't serve the obsolete version, a practice known as cache busting. One way to bust cache is to use a version number in a query string parameter when referencing the resource.

For example, if your HTML uses theme.css:

<link rel="stylesheet" type="text/css" href="theme.css">

and that, for some reason, you lose control over cached versions of the stylesheet (e.g. the stylesheet is served with the HTTP Cache-Control: public header along with an aggressive max-age that will make caches all over the wire cache it for a long time), then you can always "bust" the cache by serving this new link:

<link rel="stylesheet" type="text/css" href="theme.css?v=2">

This changes the URL of the stylesheet, meaning caches won't serve the old version. Other variants include renaming the file (theme.v2.css) or renaming the path of the file (/v2/theme.css). However those variants are a bit more complicated to implement because they require to rename the files before deploying, whereas the query string method only requires to update the reference in the HTML, since static servers simply ignore query string parameters.

You shouldn't, however, use the query string method, for the following reason: if at the moment you're serving theme.css?v=2 anyone on the Internet issues a GET request to theme.css?v=3 then caches will associate the v3 to the content of the v2. When you will want to deploy a new version and will update the query string parameter, you'll see that the resource doesn't update. A malicious client could be even more vicious and query something like theme.css?v=6 when you're at v=3 to let you see how well the system works until a few days when, updating from v=5, you try to deploy v=6 and witness the resource going back in time to its state as it was at v=3.

Using a version number in the filename is much preferable, for the simple reason that if someone requests theme.v2.css when you're serving theme.v1.css, the server will respond with a 404 error and no content, which is of course not a cacheable response.