Hugo recently introduced AVIF support for their image processing, something I have been waiting for quite a while. I was excited because AVIF is generally considered more efficient than WEBP.
Let’s look at an example from the Cycling race in 2024:
<picture class="w-[100%] ml-[0%]">
<source srcset="/2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_b7579d70d40992b1.avif 1x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_af0dede09f13f635.avif 2x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_ba489f112ee6caa8.avif 3x" type=image/avif>
<source srcset="/2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_467d840e33513384.webp 1x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_a9d99390b59f3129.webp 2x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_910d856310b4bf99.webp 3x" type=image/webp>
<source srcset="/2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_753a9b9e6ea8568f.jpg 1x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_4cc7e3233a05cc3.jpg 2x, /2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1_hu_1cb7e3f7cd42a85b.jpg 3x" type=image/jpeg>
<img src=/2024/the-uci-road-cycling-elite-mens-race-in-pictures/schwantenmos-1.75ff9b52d4278c6fefea71c81fa4c87c44f4e11aabbf93f0fd09b52e519cca0d.jpg alt width=3780 height=2088>
</picture>
The <picture> element with multiple <source> tags is doing the heavy lifting here. The browser picks the first format it supports: AVIF for modern browsers, WEBP as a fallback, and good old JPEG for the holdouts.1 Progressive enhancement at its finest.
The numbers (in theory)
How much better is AVIF, really? According to Daniel Aleksandersen’s comparison, AVIF achieves a median file size reduction of 50.3% compared to JPEG at equivalent visual quality. WEBP? Only 31.5%. And here’s the kicker: AVIF outperformed both JPEG and WEBP for every single image in the test. Not most. Every.2
For a photo-heavy blog like this sometimes is, that’s significant. Smaller files mean faster loads, less bandwidth, and happier readers on slow connections.
The quality problem (in practice)
Here’s the catch: Hugo’s AVIF files are currently larger than WEBP, not smaller. Wait, what?
The issue is how Hugo handles quality settings. Hugo uses a default quality of 75 for all formats: JPEG, WEBP, and AVIF alike. But these scales aren’t perceptually equivalent. WEBP’s quality 75 is its conventional “good lossy” sweet spot. AVIF, on the other hand, was designed with a default of around 60, and quality 60–70 in AVIF is considered comparable to WEBP at 75.
By using quality 75 for AVIF, Hugo is essentially producing higher-quality-than-necessary images, which means larger files. The fix would be per-format quality settings, something that’s being discussed but not yet implemented.
For now, you can manually set a lower quality when processing AVIF images, but it’s not ideal. I’m keeping an eye on that issue.
Speed and caching
I’ve written before about optimising Hugo builds with Cloudflare, and AVIF adds an interesting wrinkle. The encoding is slow—noticeably slower than WEBP or JPEG. Hugo’s image processing now has to do more work, which means build times go up.
The solution? Move the build to GitHub Actions and just deploy the static files to Cloudflare. Cloudflare’s build caching is limited and fiddly, but GitHub Actions has proper configurable caching that actually works. Cache the resources folder between builds, and Hugo won’t re-encode images that haven’t changed. Subsequent builds go from “coffee break” to “blink and you’ll miss it.”3
Browser support
AVIF support is essentially universal now. Chrome, Firefox, Safari, Edge—they all handle it. The only stragglers are older browser versions and some niche cases. That’s why the <picture> fallback chain matters: you serve the best format to browsers that can handle it and gracefully degrade for the rest.
Was it worth it?
Mostly. The quality is excellent, the implementation in Hugo is straightforward, and once the per-format quality settings land, the file size savings should be real. Right now it’s a bit of a wash, or even a regression, compared to WEBP, but the foundation is there.
The only downside is build time, and that’s a one-time cost per image. For a static site that rebuilds occasionally, it’s a non-issue. For a site with thousands of images and frequent deploys, maybe budget some extra CI minutes.
Now if only Hugo would add JPEG XL support.4
Yes, there are still people using browsers that don’t support WEBP. I don’t understand them either, but I respect their commitment to the old ways. ↩︎
The comparison used DSSIM (structural dissimilarity) to ensure equivalent visual quality across formats. Science! ↩︎
The trick is caching
resources/_gen/images. Hugo stores all processed images there, keyed by a hash of the source and processing options. As long as that folder persists between builds, you only pay the AVIF encoding cost once per image. ↩︎JPEG XL is arguably even better than AVIF in some ways, but Hugo doesn’t support it at all. And browser support is complicated. Safari supports it, Chrome removed it, Firefox is thinking about it. The format wars never end. ↩︎