Different ways to get an image as page resource in Hugo

In this tutorial I will focus on different ways to handle images in Hugo. Learn how to find and select images in every content and asset folder and don’t forget the fallback.

Author: Markus A. Wolf
Updated: February 2024

Get access to your images

There are several ways to get access to an image - let’s start with the easiest one.

Images inside your actual page folder

To access an image in the same folder as your markdown file you can use the following code example. This will define the variable $image with the image example.jpg

<div class="my-12">
    {{ $image := .Page.Resources.GetMatch "example.jpg" }}
    <img src="{{ $image.RelPermalink }}" alt="" class="w-96">
</div>

First image of a map

If you want to get the first image of a map, use the following code example. This example selects all jpg images beginning with example. The function index selects the first (0) element of the list and returns it to $first_image. Be aware of the bracket because the index function expects 2 values - a collection (map / list) and a key or index.

<div class="my-12">
    {{ $first_image := index (.Page.Resources.Match "example*.jpg") 0 }}
    <img src="{{ $firstImage.RelPermalink }}" alt="" class="w-96">
</div>

Images inside your actual page folder via frontmatter

One of the most use cases is selecting an image you have defined in the front matter part of your markdown file. To get access to the file name you can use .Params.image.

<div class="my-12">
    {{ $image := .Page.Resources.GetMatch .Params.image }}
    <img src="{{ $image.RelPermalink }}" alt="" class="w-96">
</div>

Add params like alt or caption to an image in front matter

In some cases you might need additional information about an image like a copyright information on a specific caption under an image. The way you can solve this in Hugo is using front matter and adding a new variable resources to your YAML part. Information inside this variable gets automatically connected to your resources based on the source file.

resources:
    - src: 'example.jpg'
      params:
          licence: MIT
          caption: 'Some more information about this image'

Don’t forget, this way to add some more details to your images is only working for images inside a page or section folder using .Page.Resources.

<div class="my-12">
    {{ $image := .Page.Resources.GetMatch "example.jpg" }}
    <img src="{{ $image.RelPermalink }}" alt="" licence="{{ $image.Params.licence }}" class="w-96">
    <p>
        {{ $image.Params.caption }}
    </p>
</div>

Images inside another page folder

This isn’t very complicated either. You can get access to a page based on an id like .File.Dir or if necessary a unique id with .File.UniqueID.

<div class="my-12">
    {{ $examplePage := index (where .Site.Pages ".File.Dir" "section/dir/") 0 }}
    {{ range $examplePage.Resources }}
        <p class="mb-4">
            {{ .Name }}<br />
            {{ .MediaType }}<br />
            {{ .MediaType.Suffixes }}<br />
        </p>
    {{ end }}
</div>

Get the page id

If you aren’t sure if you use the right id, you can always range through all pages and log every page id with this few lines of code.

<div class="text-md my-12">
    {{ range .Site.AllPages }}
    <p class="mb-4">
        Dir: {{ .File.Dir }}
        <span class="block text-sm">Path: {{ .File.Path }}</span>
        <span class="block text-sm">UniqueID: {{ .File.UniqueID }}</span>
    </p>
    {{ end}}
</div>

Get a specific image in your project

If you want to search for a specific image in your entire project just go through all pages and search for the image name.

<div class="my-12">
    {{ $search_image := ""}}
    {{ range where .Site.Pages ".Section" "blog" }}
        {{ with .Page.Resources.GetMatch "media.jpg" }}
            {{ $search_image = . }}
        {{ end }}
    {{ end }}
    <img src="{{ $search_image.RelPermalink }}" alt="" class="w-96">
</div>

GetMatch always returns one element and Match always returns a map / list even if there aren’t any images. Just remember to use index together with Match if you don’t use range.

Get the latest image of a section

<div class="my-12">
    {{ $first_image_by_date_ := index (where .Site.Pages ".Section" "blog").ByDate.Reverse 0 }}
    <img src="{{ $first_image_by_date_.RelPermalink }}" alt="" class="w-96">
</div>

Images inside your assets folder

To get access to images of your assets folder aka global resource folder you have to know more about the folder structure in Hugo. The folder /assets contains all files which need to be processed by Hugo. Only the files whose .Permalink or .RelPermalink are used in a layout will be published to the public directory. Assets directory is not created by default and should be in the root of your project.

<div class="my-12">
    {{ $image := resources.Get "/media/img/example.svg" }}
    <img src="{{ $image.RelPermalink }}" alt="" class="w-96">
</div>

Handling images in the /static folder doesn’t work. If you want to process or use images inside of Hugo, you have to move them into the /content or /assets folder.

Get all images of your entire project sorted by file name

I made up this example to show that even this is easily doable in Hugo. The first step is to define a variable as a slice to be able to append new elements. Next step is to range through all pages and append every image of a page to the variable and the last step is sorting and rendering it as HTML.

<div class="my-12">
    {{ $all_images := slice }}
    {{ range .Site.Pages }}
        {{ $all_images = $all_images | append (.Page.Resources.ByType "image") }}
    {{ end }}
    {{ range sort $all_images ".Name" "asc" }}
        <p class="text-md">
            {{ .RelPermalink }}
            {{ if .Params }}
                <span class="block text-xs mb-4"> {{ printf "%#v" .Params }}</span>
            {{ end }}
        </p>
    {{ end }}
</div>

Always have a fallback

In most cases everything works fine but maybe sometimes you have a typo or missed the right name and then your build breaks. This shouldn’t happen so here is a great way to avoid breaking builds with the glorious function: default.

default allows you to set a default value that can be returned if the first value is not set. A default value does not need to be hard coded, it can be a variable or pulled directly from front matter - the YAML part of your markdown file.

In some examples you might see the Hugo with function used to handle a default value. This is working - Yes - but blows up your code and is not as powerful as default if it comes to fallback handling. Here is an example of how to use default.

<div class="my-12">
    {{ $image := .Page.Resources.GetMatch (.Params.cover | default "example.jpg") }}
    <img src="{{ $image.RelPermalink }}" alt="" class="w-96">
</div>

Hint: Don’t miss to set the brackets right 😃

If you use an empty variable as fallback you have to wrap it inside an if condition. This is important because there might be no URL for the image and your build brakes.

<div class="my-12">
    {{ $image := resources.Get "/media/img/example.svg" | default "" }}
    {{ if $image }}
        <img src="{{ $image.RelPermalink }}" alt="" class="w-96">
    {{ end }}
</div>

All links in a practical list

More articles

Thoughts, topics or just solutions I would like to make available to you, colleagues and fellow enthusiasts.