Skip to main content
Photo by Maksym Kaharlytskyi via Unsplash

Creating a Hugo site index

I recently cut out a feature from this website that exported all the content to a JSON file, which I then used to populate my Algolia search index. However, I removed this functionality because I found a more efficient search engine for my small blog.

Because it could be helpful for other use cases that need a complete copy of their content, I decided to share the process I followed in this blog post.

Step 1: Creating a custom output format

The first step is to create a custom output format in Hugo. This is done by adding the following to your config.toml file:

2  [outputformats.DNBINDEX]
3    baseName = 'dnbindex'
4    isPlainText = true
5    mediaType = 'application/json'
6    notAlternative = true
8  home = ['DNBINDEX', 'HTML', 'RSS', 'JSON']
 3    baseName: dnbindex
 4    isPlainText: true
 5    mediaType: application/json
 6    notAlternative: true
 8  home:
10  - HTML
11  - RSS
12  - JSON
 2   "outputformats": {
 3      "DNBINDEX": {
 4         "baseName": "dnbindex",
 5         "isPlainText": true,
 6         "mediaType": "application/json",
 7         "notAlternative": true
 8      }
 9   },
10   "outputs": {
11      "home": [
12         "DNBINDEX",
13         "HTML",
14         "RSS",
15         "JSON"
16      ]
17   }

The [outputs] configuration part probably already exists in your config.toml file or configuration structure. Still, you need to add the DNBINDEX output format to the list of outputs. You need to add this to the home output.

Step 2: Create a template for the output format

Let’s create a layout template for our new output format at layouts/_default/list.dnbindex.json:

 1{{- $.Scratch.Add "index" slice -}}
 2{{- $section := $.Site.GetPage "section" .Section -}}
 3{{- range .Site.RegularPages -}}
 4  {{- if or (and (.IsDescendant $section) (and (not .Draft) (not .Params.private))) $section.IsHome -}}
 5    {{- $.Scratch.Add "index" (dict
 6      "objectID" (sha1 .Permalink)
 7      "date" (time.Format "Monday, Jan 2, 2006" .Date)
 8      "description" .Description
 9      "expirydate" .ExpiryDate.UTC.Unix
10      "fuzzywordcount" .FuzzyWordCount
11      "keywords" .Keywords
12      "kind" .Kind
13      "lang" .Lang
14      "lastmod" .Lastmod.UTC.Unix
15      "permalink" .Permalink
16      "publishdate" .PublishDate
17      "relpermalink" .RelPermalink
18      "html" .Params.Description
19      "title" .Title
20      "type" .Type
21      "url" .Permalink
22      "section" .Section
23      "tags" .Params.Tags
24      "categories" .Params.Categories
25      "author" .Params.authors
26      "content" .Params.Description
27      )
28    -}}
29  {{- end -}}
30{{- end -}}
31{{- $.Scratch.Get "index" | jsonify -}}

Looking at this layout, you can see how old it is ;) Nobody in their right mind would use a scratch these days to create a list of pages. But it works, so I won’t spend time finding out how to do it better. As I wrote above, I do not need an individually created search index. You can add as much or less information as you like in the loop that makes the dict for your pages. Reading length and word count might be nice in your search results.

Step 3: Use the index

After setting the index file up as described in steps 1 and 2, you can now run hugo to generate the index. You can find it in public/list.dnbindex.json. In my build routine, I let hugo create this file, then uploaded it to Algolia and removed it from the output before uploading my website to the production site.