Using data with Hugo

Use data files to import existing data or have an easy way of managing global data.

Farrel Burns, Developer Evangelist
Duration: 2 hours
Expertise level: Beginner
On this page:

Loading...

Code

Clone: git clone https://github.com/CloudCannon/hugo-learn-blog-template.git

Starter branch: git checkout data-intro-start

Finished lesson: git checkout data-intro-finish

What you’ll learn here:

  • What “data” is in Hugo

  • How to create and structure data

  • Practical use case for data

What is "data" in Hugo?

In the world of static sites/Jamstack, there is - by design - no database you can query directly. However, having access to supplemental data is still something that many people might still want. Naturally, you can put data into front matter, but sometimes it’s nice to have the flexibility to have it available from anywhere across your site.

This is where data files come in. A data file acts as a mini database that stores information, which Hugo gives you easy access to through simple conventions.

Additionally, Hugo has built-in functions to get data (in forms such as JSON and CSV) from external sources, such as APIs. Here, we’ll simply focus on data files local to your site.

Creating and using local data

Fortunately, there isn’t too much to set up or even learn conceptually when it comes to data, so we can get straight into using it.

How to create and access data

  • In the root of your project, simply create a folder called data. Hugo knows to look for this.
  • From the static folder, move the locations.yml and staff.yml files into this folder. YAML, TOML, or JSON are all acceptable formats, we’ll use YAML here because it’s more human-readable.
  • Then, anywhere in your layouts or shortcodes, you can access the data:
.Site.Data.<filename without extension>
.Site.Data.<filename without extension>

Depending on your setup/code scope, you might need to use $.Site to refer to global scope.

Use case 1 - location map

A classic use case for data on a static site is in an interactive map. We’ll do exactly this with OpenStreetMap and Leaflet because it’s very easy to set up and you don’t need an API key.

To make things easier, a few things have already been set up:

  • Imports for Leaflet’s JS and CSS in the head of baseof.html
  • static/map.js ****with the necessary JavaScript code for working with Leaflet and OpenStreetMap. This isn’t the focus of the lesson, but feel free to look at it/modify it.
  • A basic content file: content/locations.md.

Now all we need to do is use our global data with our JavaScript map code. To do this, let’s create another shortcode to render the map. Create shortcodes/map.html with the following contents:

\n\n"};
<div id="map-canvas"></div>
<script>
    let markers = {{ $.Site.Data.locations }};
</script>
<script src="/map.js"></script>

Finally, add the map shortcode to the content/locations.md page, below the front matter:

# Endangered bird locations
{{< map >}}
# Endangered bird locations
{{< map >}}

Simple as that! When we view the /locations page in the browser, we should see a map with some markers on it. We can easily add more markers to the data file and it will be populated when Hugo next builds the site.

Data use case 2 - list of staff

Another potential use for data is information about people, such as employees, conference attendees, or contacts.

One thing that might make sense in our case is to provide staff contact details for sightings of rare birds. Any new locations could then be added to the locations.yml file. We already have staff.yml in our data folder, with some simple contents (randomly generated names and a placeholder image location). As before, let’s create a shortcode for the situation, which we will use in our locations and about pages.

First, create shortcodes/staff.html and add this content:

<div class="contact">
    <h2 class="contact__heading">{{ with .Get "title" }}{{ . }}{{ else }}Our amazing team{{ end }}</h2>
    <p>If you think you've spotted an endangered species, please contact one of our friendly staff to let them know.</p>
</div>
<div class="staff">
    {{ range .Site.Data.staff }}
        <div class="staff-member">
            <img class="staff-member__image" src="{{ .image }}">
            <div>
                <p class="staff-member__name">{{ .name }}</p>
                <p>Contact options: </p>
                <ul class="staff-member__contacts">
                    <li><a class="option" href="#">Email</a></li>
                    <li><a class="option" href="#">Facebook</a></li>
                    <li><a class="option" href="#">Twitter</a></li>
                </ul>
            </div>
        </div>
    {{ end }}
</div>

This will generate a very basic block containing staff names and placeholder images. We can also change the title of the block if we want.

Next, add the following to content/location.md and content/about.md:

<!-- locations.md -->
{{< staff title="Report a sighting">}}
<!-- about.md -->
{{< staff >}}

This will output all of our staff information, including names and images. If we want to add more information or more staff, such as social media, it is now much easier to manage.

What’s next?

That’s it for this Hugo beginner tutorial. There are many more, smaller things to learn in Hugo, which are best put to use in the context of an improved, real-world site, such as a small business or even e-commerce site. With Hugo and JavaScript for interactions, just about any type of site is possible. 

Of course, Hugo is not a CMS. If you wish to deploy your site into the wider world and have other people contribute to it - especially non-technical people - CloudCannon offers an easy-to-use CMS solution.