You can convert your articles into JSON objects by creating a series of templates in your theme. These templates can adhere to any JSON schema you choose.
The JSON output format is advantageous for documentation sites because it can be used to build search indexes, chatbots, dashboards, and other applications that require structured data.
Before you start #
- Review the Page Kinds Hugo Documentation
- Review the Front Matter Hugo Documentation
- Review the Page Methods Hugo Documentation
How to create JSON output #
Create json.json partial #
This template acts as the core of your JSON Schema definition. It will be used across all of the other page kind layouts we’ll build (single.json, section.json, list.json, home.json).
Navigate to your theme’s
layouts/partialsdirectory.Create a new file called
json.json.Define the schema you want. Here is an example:
json{ "id": "", "version": "", "title": "", "description": "", "date": "", "draft": "", "hidden": "", "lastCommit": "", "section": "", "parent": "", "pageKind": "", "content": "", "permalink": "", "relPermalink": "" }Add golang template logic to each attribute. This requires you to use a series of page methods for pulling in data. If you’d like to use a custom front matter attribute, such as a cascaded
versionnumber from a parent directory’s_index.md, remember to use the.Paramsmethod to access it.go{ "id": "{{ .File.UniqueID }}", "version": "{{.Params.version}}", "title": "{{ .Title }}", "description": "{{ .Description }}", "date": "{{ .Date }}", "draft": {{ .Draft }}, "hidden": {{ .Hidden }}, "lastCommit": "{{ .GitInfo.AuthorDate }}", "section": "{{ .Section }}", "parent": "{{ .Parent }}", "pageKind": "{{ .Type }}", "bundleType": "{{ .BundleType }}", "content": "{{ .Content }}", "permalink": "{{ .Permalink }}", "relPermalink": "{{ .RelPermalink }}", }You can conditionally include or exclude certain attributes. For example, you can exclude the
hiddenattribute if it is not set in the front matter.go{{- with .Page.Params.hidden -}}"hidden": {{- . -}},{{- end -}}Save the file.
Create default layouts #
single.json #
This template will be used to render the JSON object for the page page kind.
- Navigate to your theme’s
layouts/_defaultdirectory. - Create a new file called
single.json. - Add the following code:go
{{- partial "json.json" . -}} - Save the file.
section.json #
This template will be used to render the JSON object for the section page kind. A section is a page that contains an array of page kinds (that can also include other sections!). Knowing this, we need to create a recursive template that will render the JSON object for the section and all of its descendants.
- Navigate to your theme’s
layouts/_defaultdirectory. - Create a new file called
section.json. - Add the following code:go
[ {{- range $index, $page := .Pages }} {{- if ne $page.Type "json" }} {{- if and $index (gt $index 0) }},{{ end }} {{- partial "json.json" . }} {{- end }} {{- if eq .Kind "section"}} {{- template "section" . }} {{- end }} {{- end }} ] {{- define "section" }} {{- range .Pages }} {{- if ne .Type "json" }} ,{{- partial "json.json" . }} {{- end }} {{- if eq .Kind "section"}} {{- template "section" . }} {{- end }} {{- end }} {{- end }}There may be a more elegant way to define this template, but this one does work. If you come up with a better one please share! - Save the file.
list.json #
This template will be used to render the JSON object for the list page kind.
- Navigate to your theme’s
layouts/_defaultdirectory. - Create a new file called
list.json. - Add the following code:go
{{- partial "json.json" . -}} - Save the file.
home.json #
This template will be used to render the JSON object for the home page kind.
- Navigate to your theme’s
layouts/_defaultdirectory. - Create a new file called
home.json. - Add the following code:go
[ {{- range $index, $page := .Pages }} {{- if ne $page.Type "json" }} {{- if and $index (gt $index 0) }},{{- end }} {{- partial "json.json" . }} {{- end }} {{- if eq .Kind "section" }} {{- template "section" . }} {{- end }} {{- end }} ] {{- define "section" }} {{- range .Pages }} {{- if ne .Type "json" }} ,{{- partial "json.json" . }} {{- end }} {{- if eq .Kind "section"}} {{- template "section" . }} {{- end }} {{- end }} {{- end }} - Save the file.
Update Hugo configuration #
- Open your Hugo
outputsconfiguration (for example,config/_default/outputs.yaml). - Update each page kind to include JSON in the supported array.yaml
home: [ "HTML", "JSON"] page: [ "HTML", "JSON"] section: [ "HTML", "JSON"] list: [ "HTML", "JSON"] - Save the file.
Test #
- Run
hugo serverin your project directory. - Navigate to your site’s homepage and append
/index.jsonto the URL. You should see a JSON index of all of your site’s pages. You can append/index.jsonto any url whose page is built using these supported page kind layouts.
Now you can use the JSON output to build search indexes, chatbots, dashboards, and other applications that require structured data.