Now, as much as I love Hugo, the documentation can be a little bit lacking, so I post this here in the hope that maybe it’ll pop up the next time someone else is Googling an error and wondering what the hell is going wrong.

One of the things I wanted Hugo to do for me is to automatically resize the images I upload, to make them a little more light on the old download bandwidth for anyone visiting the site. As a bonus, it would be good to be able to automatically generate various different sizes and then use an HTML srcset attribute to let the device download the most appropriate version given its screen size and resolution.

All of these things are, of course, possible, as you’d expect. And when you make it work, it works well. I updated the layouts/shortcodes/figure.html code that comes with the theme I use and modified it to look like this:

{{/* get file that matches the filename as specified as src="" in shortcode */}}
{{ $srcUrl := .Get "src" | safeURL }}
{{ $src := .Page.Resources.GetMatch (printf "%s" $srcUrl) }}

{{/* set image sizes, these are hardcoded for now, x dictates that images are resized to this width */}}

{{ $tinyw := default "500x" }}
{{ $smallw := default "800x" }}
{{ $mediumw := default "1200x" }}
{{ $largew := default "1500x" }}

{{/* resize the src image to the given sizes */}}

{{ .Scratch.Set "tiny" ($src.Resize $tinyw) }}
{{ .Scratch.Set "small" ($src.Resize $smallw) }}
{{ .Scratch.Set "medium" ($src.Resize $mediumw) }}
{{ .Scratch.Set "large" ($src.Resize $largew) }}

{{/* add the processed images to the scratch */}}

{{ $tiny := .Scratch.Get "tiny" }}
{{ $small := .Scratch.Get "small" }}
{{ $medium := .Scratch.Get "medium" }}
{{ $large := .Scratch.Get "large" }}

{{ if .Get "src" }}
  <figure class="{{ with .Get "position"}}{{ . }}{{ else -}} left {{- end }}" >
    <img {{ with .Get "sizes" }}sizes='{{.}}'{{ else }}sizes="(min-width: 35em) 1200px, 100vw"{{ end }}
  {{ if ge $src.Width "500" }}
    {{ with $tiny.RelPermalink }}{{.}} 500w{{ end }}
  {{ end }}
  {{ if ge $src.Width "800" }}
    {{ with $small.RelPermalink }}, {{.}} 800w{{ end }}
  {{ end }}
  {{ if ge $src.Width "1200" }}
    {{ with $medium.RelPermalink }}, {{.}} 1200w{{ end }}
  {{ end }}
  {{ if ge $src.Width "1500" }}
    {{ with $large.RelPermalink }}, {{.}} 1500w {{ end }}
  {{ end }}'
  {{ if .Get (print $medium) }}
    src="{{ $medium.RelPermalink }}"
  {{ else }}
    src="{{ $src.RelPermalink }}"
  {{ end }}

{{ with .Get "alt" }} alt="{{ . | plainify }}" {{ end }} {{ with .Get "style" }} style="{{ . | safeCSS }}" {{ end }} />
    {{ if .Get "caption" }}
      <figcaption class="{{ with .Get "captionPosition"}}{{ . }}{{ else -}} center {{- end }}" {{ with .Get "captionStyle" }} style="{{ . | safeCSS }}" {{ end }}>{{ .Get "caption" }}</figcaption>
    {{ end }}
{{ end }}

This is based on this very useful guide by Laura Kalbag, and if you read and follow Laura’s guide thoroughly, you won’t go wrong.

OK, so what?

One problem, if you don’t read Laura’s guide thoroughly, and just cut’n’paste, you’re probably going to wonder why everything fails with the following error:

nil pointer evaluating resource.Resource.Resize

Oh Google, for the sake of others, please index that string.

The answer is: page bundles.

Page Bundles?

Hugo’s image resizing methods only work with resources that are associated with the page it is generating via a page bundle. So, if you have a hierarchy that looks like this:


It’s not going to work. You need to turn your stories into directories (otherwise known as page bundles) and then store the images in that directory, like this:


Restructure your content like this, and magically the image processing functions will work again without throwing nil pointer exceptions.

It took me much too long to work this out… Hopefully, if Google does the decent thing and indexes this page - I might save somebody else the time…