JSONFeed and Hugo

Note: Updated on June 5th 2022 to reference JSONFeed 1.1, and fix the Hugo template example.

If you’re using Hugo for your blog and you want it to support JSONFeed, a syndication format for the open web a bit like RSS and Atom, there are a couple of gotchas to be aware of that tripped me up the first time I tried to implement it myself.

First, your version of Hugo should be at least 0.20. I had 0.21, the latest at the time of writing, on my machine here, but only 0.18 on my webserver. Make sure your Hugo versions are in sync and at least 0.20.

Secondly, you need to configure Hugo to generate JSON as an output format. It doesn’t by default. Add something like this to your config.toml.

[outputs]
home = ["html", "json", "rss"]

Lastly, you need the JSON feed itself. I call mine index.json and it lives in layouts/index.json. That means it’ll be accessible from /index.json on my blog. You can put it anywhere though, since you link it in your page head. See the discovery section of the documentation.

Maybe you can use mine for inspiration.

{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{
    "version": "https://jsonfeed.org/version/1.1",
    "title": {{ .Site.Title | jsonify }},
    "home_page_url": {{ .Site.BaseURL | jsonify }},
    {{ with .OutputFormats.Get "json" -}}
    "feed_url": {{ .Permalink | jsonify }},
    {{- end }}
    "description": {{ .Site.Title | jsonify }},
    "authors": [{
        "name": {{ .Site.Author.name | jsonify }},
        "url": "https://rys.sommefeldt.uk/",
        "avatar": "https://work.sommefeldt.com/img/avatar.jpg"
    }],
    "items": [
        {{ range $index, $element := $pages }}
        {{ if $index }},{{ end }} {
            "id": {{ .Permalink | jsonify }},
            "url": {{ .Permalink | jsonify }},
            "title": {{ .Title | jsonify }},
            "content_html": {{ .Content | jsonify }},
            "summary": {{ .Summary | jsonify }},
            "date_published": {{ .Date.Format "2006-01-02T15:04:05Z07:00" | jsonify }}
        }
        {{ end }}
    ]
}

As soon as I realised JSON outputs weren’t being built by default, and that they needed at least Hugo version 0.20, it all fell into place.