Hugo Tips and Fragments

Hugo is the static site generator that is used to build the new parts of the Infinite Ink website, including this page. I use the fragments below in some of Infinite Ink’s source files.

Page contents


2020-June-11  Changed the title of this article from Hugo Fragments and Tips to Hugo Tips and Fragments.

Commenting in website source files

Commenting is useful for writing notes to yourself and for holding fragments that you have used in the past or may use in the future. To learn about the comment syntax of many languages, see Infinite Ink’s Commenting Code Cheatsheet.


In a child block layout file, do not put a comment — or anything other than blank lines — outside a define-end container:

only blank lines here

{{ define "main" }}

   Go Template code and comments here

{{ end }}

only blank lines here


1. Commenting out executable code

In the Go Template language, which is also known as Go HTML, you can comment out[1] code with the following single- or multi-line comment syntax.

{{/* Go HTML single-line comment */}}

     Go HTML

The following also work.

{{- /* Go HTML single-line comment */ -}}

{{- /*
     Go HTML
*/ -}}


2. Commenting out notes and non-executable code

In a layout file or a Markdown content file, you can comment out text (such as an English-language note to yourself) or non-executable code with the following single- or multi-line comment syntax.

<!--  HTML or Markdown single-line comment -->

    HTML or Markdown
Do not use these HTML-style comments to comment out Go Template code in a Hugo layout file. If you do, Hugo will process the code and potentially generate error messages or change the layout logic.

One-off shortcodes

Shortcodes are a way to use Go Template code within a Hugo content file. Reusable and one-off shortcodes usually live in the layouts/shortcodes/ directory but, starting with Hugo 0.52, you have the option to put a shortcode directly into a content file by using an “inline shortcode.” This is especially useful for one-off shortcodes such as the ones discussed in Fragment 3 and Fragment 4 below.

To use inline shortcodes you need to set enableInlineShortcodes to true in your Hugo config file by, for example, putting the following line in your config.yaml.

enableInlineShortcodes: true


3. “Writing in Progress” inline shortcode

On Infinite Ink’s To-Do and Done Lists, in the section Writing in Progress, there is a list of articles that have not yet been published. For production — i.e. what you see — this is a list of titles without links, but for me, when I am developing the Infinite Ink website with the hugo server command, this is a list of titles with links to these unreleased articles. I do this by putting my writing-in-progress articles in a directory named content/wip/[2][3] and by putting the following inline shortcode in Infinite Ink’s website-todo-done.asciidoc[4] content file.

{{< wip.inline >}}
<ul class="posts">

  {{ range where .Site.RegularPages.ByTitle "Section" "eq" "wip" }}

      {{ if hugo.IsProduction }}

        <em>{{ .Title }}</em>
      {{ else }}  <!-- not production -->

        <a href="{{ .Permalink }}"><em>{{ .Title }}</em></a>
      {{ end }}  <!-- end if-else -->

  {{ end }}  <!-- end range -->


{{< /wip.inline >}}


In the highlighted line above, the "eq" in the phrase "Section" "eq" "wip" is not needed because it is the default operator in a where clause. I like to specify it anyway as a note to myself about the general syntax of the Go HTML where function.


I do things to ensure that no WIP[2] article is mentioned anywhere on Infinite Ink other than Infinite Ink’s To-Do and Done Lists. For example, the tag list in a WIP article’s front matter is commented out until it is no longer a WIP.


4. “Hugo version” inline shortcode

The Tools section of the About Infinite Ink page includes this list item:

  • hugo v0.73.0/extended

Each time hugo builds the Infinite Ink site, the part after “hugo ” is generated by the following fragment in Infinite Ink’s about.asciidoc[4] content file.

v{{< hv.inline >}}
  {{- hugo.Version -}}
{{< /hv.inline >}}/extended



The dashes[5] in the delimiters {{-  and  -}} tell hugo to trim whitespace around the output of hugo.Version. These trim-whitespace delimiters must be specified exactly like this, i.e.:

  • a trailing space in the left delimiter,

  • a leading space in the right delimiter,

  • and no whitespace between either curly bracket and its dash.

Reusable shortcodes

The shortcodes in this section reside in my layouts/shortcodes/ directory and can be called from any content file by using the syntax specified in the comment at the top of the shortcode.

5. build-date


Usage syntax:

  {{< build-date >}}

Path: layouts/shortcodes/build-date.html
Purpose: display current date


{{- now.Format "2006-01-02" -}}

Here it is in action…

page built 2020-07-09
           generated by build-date shortcode

This build-date shortcode is used in the Hugo Tutorial in step 15.2. Edit home.html.


6. omnicomment


Usage syntax:

    {{< omnicomment >}}
    {{< /omnicomment >}}

Forked from:
Path: layouts/shortcodes/omnicomment.html
Purpose: comment in content file written in any markup language Hugo supports
Why 1: no comment translation needed when change file from, e.g., .md to .adoc
Why 2: comment out big chunk that contains multiple comments[6]


{{ if .Inner }}{{ end }}

Note that this is a no-op shortcode.


7. years-since and years-since-phrase



  {{< years-since YYYY >}}


  {{< years-since 2009 >}}

Path: layouts/shortcodes/years-since.html
Why: as time goes on, this will still be the approximate number of years since YYYY


{{ $thisyear := int (now.Format "2006") }}
{{ $thatyear := .Get 0 }}

{{- sub $thisyear $thatyear -}}

The above years-since shortcode returns leading whitespace so I actually use the below years-since-phrase shortcode.


If you know how to remove that leading whitespace, please comment at the bottom of this page. I’ve tried a lot of things, including Hugo’s replaceRe and trim functions.




  {{< years-since-phrase YYYY >}}


  {{< years-since-phrase 2009 >}}

Path: layouts/shortcodes/years-since-phrase.html
Why: as time goes on, this phrase will still be approximately true


{{ $thisyear := int (now.Format "2006") }}
{{ $thatyear := .Get 0 }}

{{ $difference := sub $thisyear $thatyear }}

(~{{- $difference }} years ago).

This years-since-phrase shortcode is used in the…


8. getlocal



  {{< getlocal filename >}}


  {{< getlocal >}}

Path: layouts/shortcodes/getlocal.html
Purpose: get the contents of a file located in the current leaf bundle


{{ $filename := .Get 0 }}
{{ $file := .Page.Resources.GetMatch $filename }}
{{ $file.Content }}

This shortcode is used in the source code of Infinite Ink’s qutebrowser’s like this:

{{< highlight python >}}
{{< getlocal >}}
{{< /highlight >}}

This is an example of nested shortcodes. The highlight shortcode is discussed in the next section.

Built-in shortcodes

Hugo includes built-in shortcodes, which you can read about at:

A good way to learn about writing your own shortcodes is to look at the source code of Hugo’s built-in shortcodes. This code is available on GitHub at:


9. highlight

Whenever I use Hugo’s built-in highlight shortcode and want to highlight multiple lines, I need to look up the syntax, which can look like this:

{{< highlight toml "hl_lines=1 12 31" >}}

toml code with lines 1, 12, and 31 highlighted

{{< /highlight >}}

This fragment is used below in 14. Dividing lines for config.toml tables. To learn about the highlight shortcode, see:


Escaping strings in content files from Hugo processing

10. Escaping emoji codes

In step 13.2.2. Include emoji codes in Infinite Ink’s Hugo Tutorial, I wrote about the following emoji codes.


Since I have enableEmoji: true in my config.yaml, Hugo emojifies the above strings in a content file to:


So how do you write about these strings without Hugo emojifying them? There is more than one way to escape emoji codes. The way I do it is to use an HTML entity for one of the colons in each emoji code. For example:


This trick works…

  • in some parts of a Markdown content file, but does not work in Markdown inline code or in a Markdown code block

  • throughout an AsciiDoc content file, but sometimes needs [subs="replacements"]


11. Escaping Hugo shortcodes

In a Hugo content file, shortcodes are called using either the delimiters {{< and >}} or the delimiters {{% and %}}. If you want to write about shortcodes, as I did in fragments 3, 4, 5, 6, 7, 8, and 9 above, you need to escape these strings from being interpreted as being part of actual shortcode calls. Hugo uses the following syntax to escape these delimiters in a content source file:

{{</* something */>}}

{{%/* something */%}}

If you use the above delimiters in a content file, they will be rendered in the destination file as:

{{< something >}}

{{% something %}}

And these strings will not be interpreted as shortcode calls.

I learned about escaping Hugo shortcodes in the thread How is the Hugo Doc site showing shortcodes in code blocks?


Hugo configuration

To learn about configuring Hugo, see

12. frontmatter

I use the following nested map, which is also known as a table,[7] in my config.yaml because:

  1. I want date and publishDate to mean the same thing and

  2. if no date is specified, I want a reasonably sane date (:fileModTime) to be used rather than Hugo’s default date, which is 0001-Jaunary-01.

    - publishDate
    - :filename
    - date
    - :fileModTime
    - publishDate
    - :filename
    - date
    - :fileModTime
    - lastmod
    - :fileModTime


For more about this, see’s Hugo Date vs PublishDate, which includes a post by n m (i.e. me😄).

The TOML syntax for this table is in fragment 14 below.


13. markup

Starting with Hugo v0.60.0[8], the way to override Hugo’s default markup settings is to use a markup nested map. Here is what I have in my config.yaml:

      unsafe: true  # default is false
    style: tango    # default is monokai


Note that some of the fragments on this page, including this markup YAML fragment, are displayed with tango-style highlighting.

For more about this, see the following.


14. Dividing lines for config.toml tables

When I use a config.toml, I like to include comments like the three highlighted lines below.

### ---> Put tables below non-tables <--- ###

# next from “One-off shortcodes” above
enableInlineShortcodes = true

# next from fragment 10 above
enableEmoji = true 

### ---> Put TOML tables below here <--- ###

# next from fragment 12 above
  date = ["publishDate", ":filename", "date", ":fileModTime"]
  publishDate = ["publishDate", ":filename", "date", ":fileModTime"]
  lastmod = ["lastmod", ":fileModTime"]

# next from fragment 13 above
      unsafe = true
    style = "tango"

### ---> Put tables below non-tables <--- ###


I use these triple-hash comments because I have spent a lot of time debugging Hugo websites when I, for example, put a non-table at the bottom of a config.toml.⁠😩


2. WIP can mean “work in progress” or “writing in progress.”
3. The front matter of some of Infinite Ink’s WIP articles include draft: true. Only the titles of the WIP articles that are not drafts are listed when I publish Infinite Ink’s To-Do and Done Lists page.
5. The Unicode name for “dash” (-) is hyphen-minus. Details are at Hyphen-minus - Wikipedia.
6. By “multiple comments,” I mean markup comments that are not omnicomments.
7. A nested map is also known as an associative array, a dictionary, a dict, a hash table, a hash, a map, a mapping, a named map, an object, or a table. For more about this data-serialization object, see Infinite Ink’s YAML includes Atoms, Maps, and Lists.
8. As of Hugo v0.60.0, which was released on 2019-November-27, Goldmark is the default Markdown parser, the Mmark Markdown parser is deprecated, and it was announced that the Blackfriday Markdown parser will eventually be deprecated.

Edit this page👍👎✍

To add a reaction or comment to this page, you need a GitHub account and your browser needs to be able to run a script that is hosted at