Hugo 0.20 introduced the powerful feature Custom Output Formats; Hugo isn’t just that “static HTML with an added RSS feed” anymore. Say hello to calendars, e-book formats, Google AMP, and JSON search indexes, to name a few.

This page describes how to properly configure your site with the media types and output formats you need.

Media Types

A media type (also known as MIME type and content type) is a two-part identifier for file formats and format contents transmitted on the Internet.

This is the full set of built-in media types in Hugo:

Type Suffix
application/javascript js
application/json json
application/rss xml
application/xml xml
text/calendar ics
text/css css
text/csv csv
text/html html
text/plain txt


  • It is possible to add custom media types or change the defaults (if you, say, want to change the suffix to asp for text/html).
  • The Suffix is the value that will be used for URLs and filenames for that media type in Hugo.
  • The Type is the identifier that must be used when defining new Output Formats (see below).
  • The full set of media types will be registered in Hugo’s built-in development server to make sure they are recognized by the browser.

To add or modify a media type, define it in a mediaTypes section in your site config (either for all sites or for a given language).

Example in config.toml:

suffix = "enr"
suffix = "asp"

The above example adds one new media type, text/enriched, and changes the suffix for the built-in text/html media type.

Output Formats

Given a media type and some additional configuration, you get an Output Format.

This is the full set of built-in output formats in Hugo:

Name MediaType Path BaseName Rel Protocol IsPlainText IsHTML NoUgly NotAlternative
AMP text/html+html amp index amphtml false true false false
CSS text/css+css styles stylesheet true false false true
CSV text/csv+csv index alternate true false false false
Calendar text/calendar+ics index alternate webcal:// true false false false
HTML text/html+html index canonical false true false false
JSON application/json+json index alternate true false false false
RSS application/rss+xml index alternate false false true false


  • A page can be output in as many output formats as you want, and you can have an infinite amount of output formats defined, as long as they resolve to a unique path on the file system. In the table above, the best example of this is AMP vs. HTML: We have given AMP a value for Path so it doesn’t overwrite the HTML version, i.e. we can now have both /index.html and /amp/index.html.
  • The MediaType must match the Type of an already defined media type (see above).
  • You can define new or redefine built-in output formats (if you, as an example, want to put AMP pages in a different path).

To add or modify a media type, define it in a outputFormats section in your site config (either for all sites or for a given language).

Example in config.toml:

mediaType = "text/enriched" 
baseName = "myindex"
isPlainText = true
protocol = "bep://"

The above example is fictional, but if used for the home page on a site with baseURL, it will produce a plain text home page with the URL bep://

All the available configuration options for output formats and their default values:

Field Description
Name The output format identifier. This is used to define what output format(s) you want for your pages.
MediaType This must match the Type of a defined media type.
Path Sub path to save the output files.
BaseName The base filename for the list filenames (home page etc.). Default: index.
Rel Can be used to create rel values in link tags. Default: alternate.
Protocol Will replace the “http://” or “https://” in your baseURL for this output format.
IsPlainText Use Go’s plain text templates parser for the templates. Default: false.
IsHTML Used in situations only relevant for HTML type of formats, page aliases being one example.
NoUgly If uglyURLs is enabled globally, this can be used to turn it off for a given output format. Default: false.
NotAlternative Enable if it doesn’t make sense to include this format in an the .AlternativeOutputFormats format listing on Page, CSS being one good example. Note that we use the term “alternative” and not “alternate” here, as it does not necessarily replace the other format, it is an alternative representation. Default: false.

Output Formats for your pages

A Page in Hugo can be rendered to multiple representations on the file system: In its default configuration all will get an HTML page and some of them will get an RSS page (home page, sections etc.).

This can be changed by defining an outputs list of output formats in either the Page front matter or in the site configuration (either for all sites or per language).

Example from site config in config.toml:

 home = [ "HTML", "AMP", "RSS"]
 page = [ "HTML"]


  • The output definition is per Page Kind(page, home, section, taxonomy, taxonomyTerm).
  • The names used must match the Name of a defined Output Format.
  • Any Kind without a definition will get HTML.
  • These can be overriden per Page in front matter (see below).

A Page with YAML front matter defining some output formats for that Page:

 date: "2016-03-19"
 - html
 - amp
 - json

Note that the names used for the output formats are case insensitive.

Page has both .OutputFormats (all formats including the current) and .AlternativeOutputFormats, the latter useful for creating a link rel list in your head section:

 {{ range .AlternativeOutputFormats -}}
 <link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
 {{ end -}}

Note that .Permalink on RelPermalink on Page will return the first output format defined for that page (usually HTML if nothing else is defined).

This is how you link to a given output format:

{{ with  .OutputFormats.Get "json" -}}
<a href="{{ .Permalink }}">{{ .Name }}</a>
{{- end }}

From content files, you can use the ref or relref shortcodes:

[Neat]({{< ref "blog/" "amp" >}})
[Who]({{< relref "" "amp" >}})

Templates for your Output Formats

Of course, for a new Output Format to render anything useful, we need a template for it.

The fundamental thing to understand about this is that we in Hugo 0.20 now also look at Output Format┬┤s Name and MediaType┬┤s Suffix when we choose the templates to use to render a given Page.

And with so many possible variations, this is best explained with some examples:

Example OutputFormat Suffix Template Lookup Order
AMP home, with theme "demoTheme". AMP html [layouts/index.amp.html layouts/index.html layouts/_default/list.amp.html layouts/_default/list.html demoTheme/layouts/index.amp.html demoTheme/layouts/index.html demoTheme/layouts/_default/list.amp.html demoTheme/layouts/_default/list.html]
JSON home, no theme. JSON json [layouts/index.json.json layouts/index.json layouts/_default/list.json.json layouts/_default/list.json]
CSV regular, "layout: demolayout" in front matter. CSV csv [layouts/_default/demolayout.csv.csv layouts/_default/demolayout.csv]
JSON regular, "type: demotype" in front matter. CSV csv [layouts/demotype/single.csv.csv layouts/demotype/single.csv layouts/_default/single.csv.csv layouts/_default/single.csv]
HTML regular. HTML html [layouts/_default/single.html.html layouts/_default/single.html]
AMP regular. AMP html [layouts/_default/single.amp.html layouts/_default/single.html]
Calendar blog section. Calendar ics [layouts/section/blog.calendar.ics layouts/section/blog.ics layouts/blog/list.calendar.ics layouts/blog/list.ics layouts/_default/section.calendar.ics layouts/_default/section.ics layouts/_default/list.calendar.ics layouts/_default/list.ics]
Calendar taxonomy list. Calendar ics [layouts/taxonomy/tag.calendar.ics layouts/taxonomy/tag.ics layouts/_default/taxonomy.calendar.ics layouts/_default/taxonomy.ics layouts/_default/list.calendar.ics layouts/_default/list.ics]
Calendar taxonomy term. Calendar ics [layouts/taxonomy/tag.terms.calendar.ics layouts/taxonomy/tag.terms.ics layouts/_default/terms.calendar.ics layouts/_default/terms.ics]


  • All of the above examples can use a base template, see Blocks.
  • All of the above examples can also include partials.

Hugo will now also detect the media type and output format of partials, if possible, and use that information to decide if the partial should be parsed as a plain text template or not.

Hugo will look for the name given, so you can name it whatever you want. But if you want it treated as plain text, you should use the file suffix and, if needed, the name of the Output Format ([partial name].[OutputFormat].[suffix]).

The partial below is a plain text template (Outpuf Format is CSV, and since this is the only output format with the suffix csv, we don’t need to include the Output Format’s Name):

{{ partial "mytextpartial.csv" . }}

Also note that plain text partials can currently only be included in plain text templates, and vice versa. See this issue for some background.