Hugo Tips and Tricks #1

Transforming Dynamic Data via Dispatch Strategy and Set Logic

I’ve been exploring options for dynamic rendering in Hugo.

It took a bit to stumble upon how to render an enumerable (e.g. an Array or Hash) as valid Javascript Object Notation (JSON 📖). The primary problem is how to handle the commas AND apply any transformations on the Array/Slice or Hash/Dictionary.

In Hugo, if I have a Slice {{- $slice := slice("title" "created_at" "author") }}, I can use the delimit function to render that slice. For example {{ delimit $slice "; " }} would render title; created_at; author. However I need to do something different if I want to use the $slice as a key to lookup data and render that data according to its attributes.

Original JSON Document

Lets say I have a JSON document:

  "title": {
    "type": "html",
    "label": "Title",
    "value": "<h1>Hugo Demo<h1><h2>Creative Approaches to Iteration</h2>"
  "author": {
    "type": "text",
    "label": "Author",
    "value": "Jeremy Friesen"
  "created_at": {
    "type": "date",
    "label": "Date",
    "value": "2020-05-01"

Notice the trailing comma at the end of the “title” and “author” line. There is no comma at the end of the “created_at” line.

Transformed JSON Document

I want to transform the original JSON into the following Transformed JSON:

  "Title": "\u003ch1\u003Hugo Demo\u003c/h1\u003\u003ch2\u003Creative Approaches to Iteration\u003c/h2\u003",
  "Author": "Jeremy Friesen",
  "Date": "May 1, 2020"

In the transformed JSON, I’ve taken the original JSON document, and transformed it. The title attribute is JSON encoded HTML. I’ve chosen to render the date attribute in a “natural language format”.

Let’s walk through the steps. I added a ./data/attributes.json document. This conforms to Hugo’s Data Templates.


I then wrote three partials, all in the ./layouts/partials/default directory. Note: these partials map to the type attribute in the original JSON. The .label and .value references in the below templates are form the attributes of the original JSON.


"{{ .label }}": "{{ dateFormat "Jan 2, 2006" .value }}"

Note, I’m using Hugo’s dateFormat function to transform from an ISO8601 format into a “human readable” format. Normally, I would never transport JSON with a date in this “human readable” format, but this is part of the exercise.


"{{ .label }}": {{ .value | jsonify }}

The jsonify ensures that we have a compliant JSON element. It also renders the enclosing paranthesis.


"{{ .label }}": {{ .value | jsonify }}

Again, using jsonify to ensure we have compliant JSON.

Stitching it All Together

I then use the following Hugo template to render the JSON.

{{/* Here we need to gather all the keys for the attributes. We need just the
     keys, as they are strings, and can later be compared when we call the
     `complement` function. In hugo, we cannot run the `compliment` on a
     map/dict object
{{- $keys := slice }}
{{- range $key, $data := .Site.Data.attributes }}
  {{- $keys = $keys | append $key }}
{{- end }}
{{- $last_key := $keys | last 1 }}

{{/* NOTE: The next line is the open bracket for the resulting JSON document */}}
{{- range $key := ($keys | complement $last_key) }}
  {{- $predicate := index $.Site.Data.attributes $key }}
  {{- $partialName := (printf "default/%s.json" $predicate.type )}}
  {{ partial $partialName $predicate }},
{{- end }}
{{/* NOTE: The above range and below range are almost exact copies. However,
     in the above, after we render the partial, we add a comma. In the below
     range, we do not add a comma after we render the partial */}}
{{- range $key := $last_key }}
  {{- $predicate := index $.Site.Data.attributes $key }}
  {{- $partialName := (printf "default/%s.json" $predicate.type )}}
  {{ partial $partialName $predicate }}
{{- end }}
{{/* NOTE:  The next line is the close bracket for the resulting JSON document */}}


With the above Hugo template and partials, I transformed the original JSON document into a new JSON document.

I hope this provides some insight in how you might use dynamic data, render dispatching strategies, and some set logic to transform the dynamic data.

If you’d like a working example, please take a look at