Random Content from Data in Hugo

Published 21.08.2018, 5 minute read

Data in Hugo

Hugo comes with the possibility of storing structured content in a data file where it can be pulled from by the template placing it on the site. I’ve seen this used for things like pricing tables for example. There’s quite a bunch of use cases for random content on a website though, from customer references on a company website to quotes of the day for a literary blog. This use case is going to be what the following article is about.

The Setup

Let’s assume we’re creating a company or product marketing website. Wouldn’t it be nice to display an assortment of customer testimonies, success stories or customer logos there? At best, that content should change over time, so that curious readers and repeat) visitors of your site will be encouraged to check out the hypothetical /references section of the site.

For this example, we’ll stick to the customer logos, displaying them in a row across the whole page including a link to the /references page where we’ll display the complete list as a grid.

The Data

Our customers are going to be stored in a file called references.json which we’re going to place in Hugo’s Data folder.

The file’s structure is going to look like that:

        "custName": "Contoso AG",
        "custDesc": "Absolutely generic products and services.",
        "custLogo": "contosoag",
        "custLink": "https://contoso.com"

The customer logos are going to be stored in static/img/cust/, their file extension should be the same across the board (i.e. all PNG images) and their name should correspond to what’s stored as custLogo in the JSON file.

If you are going to have many different file extensions, it may be best to store the file name including its extension in your JSON file.

The Templates

We’re going to use 2 kinds of templates, one partial to display the random selection from our data file wherever we see fit and one full template for the /references page including all the customer details.

The Partial

Our partial’s purpose shall be obtaining 6 random customer logos and displaying them in a row next to each other.

The code for this procedure could look like that:

{{ range $i, $content := $.Site.Data.references | shuffle | first 6 }}
    <div class="col">
        <img class="customer-img" src="/img/cust/{{ $content.custLogo }}.png" alt="{{ $content.custName }}" title="{{ $content.custName }}">
{{ end }}

The selection of the random items is going to be triggered by the website build and each new build will create another 6 logos.

A possible implementation of the whole selection, opening with a heading and followed by some button leading to the /references page could look like this then:

<div class="row">
    <div class="col text-center">
        <h2>Customer References</h2>
        <p>These are only some of our customers...</p>
        <a href="/references" class="btn">Browse all Customer References</a>
<div class="row">
    {{- range $i, $content := $.Site.Data.references | shuffle | first 6 -}}
        <div class="col">
            <img class="customer-img" src="/img/cust/{{ $content.custLogo }}.png" alt="{{ $content.custName }}" title="{{ $content.custName }}">
    {{ end }}

In order to use this newly created partial, we’ll store it as rnd-customers.html in /themes/[theme-name]/layouts/partials/ of our Hugo site. After that, it’s available wherever we would like to display it using the syntax {{ partial "rnd-customers.html" . }}.

The Template

Now that we have got our random content, let’s see how to build a page from the JSON file as well.

In order to do that, we’ll have to make sure that the /references page exists. We’ll also have to specify a specific template for it in front matter. The markdown file could look like this:

title = "References"
layout = "reference"
description = "Information regarding our references"

## Reference Customers

The respective template references.html is stored in the /layouts/ folder and looks like that:

{{ partial "head.html" . }}
{{ partial "header.html" . }}
    <header class="header">
        <!-- Page Header Content -->
    <div class="container">
        <!-- Main Content -->
        <div class="row">
            {{- range $i, $content := $.Site.Data.references -}}
                {{- $counter :=add $i 1 -}}
                <div class="col-md-4">
                    <div class="refcard text-center">
                        <img class="img-center" src="/img/klg/{{ $content.custLogo }}.png" alt="{{ $content.custName }}" title="{{ $content.custName }}">
                        <h5>{{ $content.custName }}</h5>
                        <p>{{ $content.custDesc }}</p>
                        <p><a class="reflink" href="{{ $content.custLink }}" rel="noopener" target="_blank">Customer Website</a></p>
                {{- if modBool $counter 3 -}}<div class="clearfix"></div>{{ end }}
            {{ end }}
{{ partial "contact.html" . }}
{{ partial "footer.html" . }}

In order to have rows of 3 items in a 12 column grid that are equally spaced, I have added the $counter that will make sure to add a <div class="clearfix"> after every 3 items. Depending on the CSS you’re using, this may not be necessary - I used Bootstrap 3 in my example above and it was necessary to have each row of 3 customers line up straight.

As you may have noticed, I removed most classes that were not essential for a basic understanding of the concept from the code examples above. So, if you’re going to use them, please make sure to check carefully and add the necessary class definitions.


Working with data in Hugo is a very convenient thing to do, as the examples above may have been able to demonstrate. I’m glad I was able to discover this approach just at the right time - the thought of doing the same thing with jQuery at runtime doesn’t seem very appealing to me anymore honestly.

Leave a Comment

Confidential, will not be shared with anyone or published here.


— ttntm on Wed, 26 Aug. 2020, 14:23 UTC

Glad you found a solution, thanks for sharing. I don't know how your data looks, but I guess 'index' made it iterable enough to range over it.

— julien colomb on Wed, 26 Aug. 2020, 11:47 UTC

I think I got it using index: {{- range $i, $content := (index $.Site.Data.reference) | shuffle | first 6 -}}

— ttntm on Wed, 26 Aug. 2020, 11:42 UTC

Hi Julien, the site this is taken from runs on Hugo 0.58.0, the JSON is exactly like the example above - an array of objects like [{"name": "one"}, {"name": "two"}, {"name": "three"}]. The error you are receiving suggests that you're not dealing with an array - see: https://discourse.gohugo.io/t/shuffle-on-site-data-cant-iterate-over-map-string-interface/4463 I'd suggest trying with a newly created simple JSON input file to rule out template issues.

— julien colomb on Wed, 26 Aug. 2020, 11:21 UTC

getting forward, it works only with json document with only one element. ``` error calling shuffle: can't iterate over map[string]interface ```

— julien colomb on Wed, 26 Aug. 2020, 11:10 UTC

can't make it to work... is there any website/github space where we can see it work ? (I am using an old academic themes running on an old version of hugo, a lot of reason for it not too work...)

Related Posts

Building a Store Locator Based on Leaflet

A detailed article about building a store locator based on Leaflet into a static site generated by Hugo.

Published 15.03.2020, 9 minute read

jQuery Multiselect Filter

An article about building a portfolio filter capable of multiselect with jQuery. Also includes a working CodePen example.

Published 12.12.2018, 7 minute read