Iāve recently moved my personal website to Hugo, and itās been mostly a pleasant experience switching over from Jekyll. I got tons of improvements in build time. But what didnāt work so well for me was the Hugo documentation. It all relies on the idea that youāll install Hugo, create a new site, and then add a theme. Here is where the problem starts. I didnāt want a stock theme, itās my personal website after all, so it should be an expression of myself, right? Well, I was lucky enough to catch Hui Jing in a benevolently, slightly bored, mood. She created all the custom CSS for it, with a fantastic Masonry layout.
But that meant from this point forward the Hugo docs were mostly useless. They are geared towards helping you either develop a theme or change your theme to accomplish something new. Mine wasnāt a very complicated Hugo website, to begin with, so following in Hui Jingās footsteps, we made it work without docs. Now that the āMVPā has been released for a few months, I keep finding small, little things to improve with it. Or if you look at my web.dev scores, not so little. š

Before
I had my cover image in the post front matter, under the images
list, because that was the Hugo way to automatically make that image a Twitter social card as well. Me being lazy, I considered that a win š¤¦āāļø. I also had my images stored in the static/
folder, because that made sense? I mean images are not exactly content or assets, right? Turns out itās wrong, but more on that later.
That meant using images in my articles was easy. I write them in markdown
, so adding an image was just a matter of putting the right path in there:
For the layouts, thatās where things became tricky. Technically the front matter images
are an array, even if it only ever had one element. That meant I had to cycle through those elements when I displayed them on the list
layouts. Or get the item at index 0. So the code ended up looking a little messy.
There were a few problems with this approach.
- I was too lazy to bother resizing all the images for the
list
layout, so most of them were quite big and loaded all at once on the home page. Slow was an understatement. - I couldnāt be bothered to resize images multiple times to do responsive images. Ideally 3-4 times. Hence the horrible performance score on Lighthouse.
There seemed to be a light at the end of this tunnel though. Skimming through the docs, it looked like there was something called Image Processing in Hugo, and that was supposed to help fix all my problems. I could resize my images at build time while compressing them and changing the encoding quality. It all sounded like an easy fix for my laziness. Except the docs are a bit on the slim side, and they werenāt really useful for a website without a Hugo theme. Iāve given it a try twice so far with no luck, but it looks like third time is the charm.
How to Add Image Processing to Hugo
The first thing I was doing wrong was the fact that images were in the static
folder. Image Processing in Hugo works on Resources, and for it to work, the image has to be either a Page Resource or a Resource. Page Resources have to live in the same folder as the markdown file, so that was out of the question. There were way too many images to move around, and too many paths to change in every article. The other option, Resource, meant the images have to live in the assets
folder, so that was an easy drag-and-drop. Didnāt even have to change the relative paths in the articles front matter.
First thing I did was to move my images into the assets
folder instead of static
. I changed my images to live from /static/img
to /assets/img
. Which meant my image sources in articles stopped working altogether. The assets donāt get generated at build time unless theyāre processed. And even then, their file name is dynamically generated with every build. So I had to change all image occurrences in the articles and templates to use the Resource instead.
For that to work in my content files, I had to create a shortcode, itās the Hugo way to have snippets inside Markdown. Hereās how mine looks like, Iāve taken the responsive images shortcode Laura Kalbag blogged about and changed it to suit my layout. And because I have animated GIFs in my DevTricks series, Iām not resizing those, just passing the relative permalink to an image tag. Iām also not doing anything to external images. Still, I figured making everything play nicely with alt tags would score me some Lighthouse points.
To use this image shortcode in my content, I had to change the way my links were called from the default markdown syntax to something in between Hugo and HTML:
The output of the {{< img >}}
shortcode looks a bit similar to this:
It looked like I could resize my images inside content. So why wouldnāt I be able to do the same in my layouts? Because somewhere in the fine print on the docs it says I canāt use shortcodes outside of content files. Still, the same functionality is available in layout templates via partial templates. As it turns out, I donāt need responsive images on my list views, I just need way smaller images. So I didnāt bother recreating the whole shortcode logic in partial templates. Instead, I had a less complicated, lazier approach. I get the image Resource, I resize it to 360px, with a quality of 85%, using a Box filter. It all translates to smaller, faster, poorer quality images on the home page.
After
With these changes, I was ready to test my Lighthouse score again. You can try as well, my website is alexlakatos.com.
Youāll notice my Largest Contentful Paint
went down by about three and a half seconds. Iād call that a win. The Performance score also went up to 99, which Iād call pretty darn good. The fact that both my Accessibility and SEO scores jumped to 100 is because the new shortcode made me re-write all my image tags. I took the time to update them to have an alt
attribute, so I wouldnāt have to go through them again.
Now if I wanted to do more, I would have to figure out a way to make Hugoās Image Processing pipeline work with next-gen image formats. But thatās a story for another time. In the meantime, feel free to reach out on Twitter, and let me know if youāve found this useful. Or at least mildly entertaining.š