You should for sure be setting far-out cache headers on your assets like CSS and JavaScript (and images and fonts and whatever else). That tells the browser “hang on to this file basically forever.” That way, when navigating from page to page on a site — or revisiting it, or refreshing the page — the browser doesn’t have to download it again which produces way faster page loads. It’s massively important for web performance, so do it!

But how do you force the browser to get a fresh version of the file? Well, there are a bunch of ways. Check out that blog post for more. But here’s one that I’ve used just recently that I wanted to document.

The trick is to change the query string

There was an era where the prevailing wisdom was that changing the query string wasn’t enough, but even then it, the reasons it wouldn’t work were pretty much edge cases. These days, changing the query string is fine (assuming you don’t change the default behavior, services like Cloudflare let you do it).

So, one day you ship it like this in your HTML:

<link rel="stylesheet" href="style.css?v=1" />

Then you change that query string to break the cache when you need to:

<link rel="stylesheet" href="style.css?v=2" />

The HTML, by the way, is either not cached or cached for a much shorter amount of time, so changes to HTML will be seen.

I sometimes do it by hand

For many years, I busted cache on this very site by setting a PHP variable and using it to break assets, like…

<?php $ver = 1.0; ?> <link rel="stylesheet" href="style.css?v=<?php echo $ver; ?>" /> <link rel="stylesheet" href="some-other-asset.css?v=<?php echo $ver; ?>" />

Hey that works, but it was me hand-manipulating that variable. I would sometimes forget to do it, and even if I did remember, I sort of resented having to do it.

Automating version busting with Gulp

I’m using a Gulp-powered build process at the moment on this site, which does all the classic stuff: Sass, Babel, file concatenation, live reloading…

It occurred to me I might as well have Gulp do the query-string changing whenever changes are made to CSS or JavaScript. JavaScript has a .replace() method, and that’s available in Node/Gulp easily with the gulp-replace plugin.

I make a task. When I call it, it looks in my header filer for the string cache_bust= plus some value, and replaces it with a new randomized string based on the date and time.

gulp.task("cache-bust-css", function() { var cbString = new Date().getTime(); return gulp .src(["header.php"]) .pipe( replace(/cache_bust=\d+/g, function() { return "cache_bust=" + cbString; }) ) .pipe(gulp.dest(".")); });

I do the same thing in a separate task when JavaScript files are editing and compiled.

It’s still a little dumb

Notice that I’m changing the query string on all the CSS assets every time any of them changes. That’s not as efficient as it could be. I should probably be changing the query string only on the changed files.

I’ll get to it eventually. Sometimes you just gotta baby-step your way to better solutions over time.

This is just one way! There are other Gulp plugins just for this. Other build systems have different approaches. This approached happened to work well for me and my exact needs at the time. Feel free to share your strategy!