Cache Busting with Hugo Pipes

When I set this site up on Amazon S3 and CloudFront, I enabled caching to improve overall performance. However, caching can become an issue when you want to update files frequently — such as stylesheets — and ensure that the very latest version of that file is being served.

I knew that with CloudFront I could invalidate cached files and therefore force it to serve the latest version, but this is a slow, manual process that can also incur fees. Alternatively, I knew that I could use some form of versioned file names to ensure that the latest version of a file is being served (basically make sure the file being requested has a unique file name so that the newly updated file won’t be served from the cache), but I wasn’t sure how do this using Hugo — the static site generator behind this blog.

Enter Hugo Pipes

I’m very new to Hugo, so when I started looking for a solution, I wasn’t aware of Hugo Pipes. After much searching, I happened upon a great writeup on Hugo Pipes by Regis Philbert that explained what they are and how to use them.

Hugo Pipes are a set of functions that allow you to run processes on certain files during the build phase. As it turns out, there’s a Hugo Pipes function that’s perfect for solving this caching issue called fingerprint.

This function allows you to add a sha256 hash to the end of a file name when it has been updated. This means that every time you update that file, it will have a unique file name, so the next time someone visits the site, the new file will be requested instead of the cached — and now outdated — version of the file.

The Solution

Here’s how I implemented fingerprint with this site’s CSS file. I’ll break it down further below.

    {{ $style := resources.Get "css/blog.css" | fingerprint }}
    <link rel="stylesheet" href="{{ $style.Permalink }}">

First, we’re setting the file that we want to modify (in this case blog.css) to a variable named $style:

{{ $style := resources.Get "css/blog.css" }}

Next, we’re defining the Hugo Pipes function that we want to run on this file — in this case fingerprint:

{{ $style := resources.Get "css/blog.css" | fingerprint }}

Finally, we pass the $style variable as a Permalink to our stylesheet’s <link> element and we’re done:

<link rel="stylesheet" href="{{ $style.Permalink }}">

This results in the processed file having a unique file name like this:

<link rel="stylesheet" href="/css/blog.min.27b33892dc3fb63a8d19bbe7df41b205.css">

To learn more about Hugo Pipes and all the different functions that are available, check out the Hugo Pipes Introduction documentation.