This blog, like many websites around the web, is hosted on Cloudflare. While many sites use Cloudflare simply as a reverse proxy and DDoS mitigation service, I also take advantage of their excellent Pages. It’s a mature product that demonstrates what is possible with a “serverless” architecture.
Now, the entire serverless aspect isn’t that relevant to me—at least not for this blog—since it’s statically generated using Hugo. Hugo is outstanding, producing highly optimised sites and, in my opinion, offering a refreshing alternative to the many websites built on frontend frameworks that are often unnecessary1.
By using Cloudflare Pages, I don’t even build my site locally2. Instead, I push it to GitHub, where it’s automatically built and deployed to Cloudflare’s content delivery network. This means the build process happens on Cloudflare’s servers, which is cool—but it puzzles me that Cloudflare doesn’t leverage any caching for Hugo builds.
Hugo: As Fast as It Gets
Hugo is fast. It says so on their website, and others agree. For me, it’s simple: Hugo’s speed means it never gets in the way.
When generating plain text, Hugo is so fast you might miss it if you blink3. Of course, more advanced features (of which Hugo has plenty) can take slightly longer.
Hugo Assets and Pipes
As websites grow in complexity, so do their build processes. Fortunately, Hugo has a fantastic feature: when something takes more than a trivial amount of time4, it caches the result. This applies to image processing and remote resources, among other things.
Image Optimisation
Take this image, one of my favourites from a recent Sunday morning hike:

This image isn’t technically remarkable—it was taken with my phone. Since there was plenty of light, the quality is high. I also enabled RAW Max mode, producing a 48-megapixel Apple ProRAW file. This format isn’t practical for the web, so I exported it to JPEG.

While the resolution didn’t change, the JPEG file is about 3–4 times smaller than the original RAW file. However, at almost 25 MB, it’s still far too large for a speedy website. Images on this blog display at a maximum of 656 pixels, so this one is more than 12 times too large—clearly, there’s room for optimisation.
Modern Image Formats and Responsive Design
Today, various devices access this blog—from high-resolution smartphones to large desktop monitors. To optimise for these scenarios, modern browsers support efficient formats like WebP5.
Using the <picture>
tag, I generate both WebP and JPEG formats at multiple resolutions. This ensures responsive design while significantly reducing file sizes, thanks to both resizing and format efficiency.

For every image on this blog, six different files are generated. This takes time, but Hugo’s caching makes it manageable.
Cloudflare Build Process
While Hugo’s local builds are seamless, Cloudflare Pages uses a different approach. Unfortunately, it doesn’t utilise caching during the build process. This means that instead of calculating image sizes once and reusing the results, Cloudflare repeats the process every time.
As shown below, Cloudflare’s servers are slightly slower than my overpowered laptop. However, the real difference lies in the lack of caching:

While I don’t monitor build times closely, it seems odd that Cloudflare doesn’t turn on caching for Hugo builds. They even document a build caching process—it’s just not enabled for Hugo. This could save time and, more importantly, reduce Cloudflare’s server load.
Given that they offer 500 free builds per month without time limitations, you’d think they’d want to save computing cycles. Enabling caching for Hugo builds seems like an easy win for everyone.
Frontend frameworks are absolutely justified for dynamic functionality, but for something like a blog, they’re usually overkill. ↩︎
I do run Hugo locally when writing or developing, but only for previewing via
hugo server
rather than creating an optimised build. ↩︎Building around 100 pages takes about 0.05 seconds. By comparison, the average blink lasts 0.15–0.2 seconds. ↩︎
“Very quick” is my favourite metric—basically, it’s faster than you’d notice. ↩︎
While WebP images don’t always show dramatic differences, I’ve seen similar quality with file sizes nearly halved. ↩︎