The documentation of the Hugo static site generator in one long page
Switch branches/tags
Nothing to show
Clone or download

This is the documentation of Hugo condensed into one long page. I did this to make the documentation easier to search and navigate. This page was automatically generated using a Python script using the documentation available at Hugo's GitHub repository.














About Hugo

Hugo is not your average static site generator.

What is Hugo

Hugo is a general-purpose website framework. Technically speaking, Hugo is a static site generator. Unlike systems that dynamically build a page with each visitor request, Hugo builds pages when you create or update your content. Since websites are viewed far more often than they are edited, Hugo is designed to provide an optimal viewing experience for your website's end users and an ideal writing experience for website authors.

Websites built with Hugo are extremely fast and secure. Hugo sites can be hosted anywhere, including Netlify, Heroku, GoDaddy, DreamHost, GitHub Pages, Surge, Aerobatic, Firebase, Google Cloud Storage, Amazon S3, Rackspace, Azure, and CloudFront and work well with CDNs. Hugo sites run without the need for a database or dependencies on expensive runtimes like Ruby, Python, or PHP.

We think of Hugo as the ideal website creation tool with nearly instant build times, able to rebuild whenever a change is made.

How Fast is Hugo?

{{< youtube "CdiDYZ51a2o" >}}

What Does Hugo Do?

In technical terms, Hugo takes a source directory of files and templates and uses these as input to create a complete website.

Who Should Use Hugo?

Hugo is for people that prefer writing in a text editor over a browser.

Hugo is for people who want to hand code their own website without worrying about setting up complicated runtimes, dependencies and databases.

Hugo is for people building a blog, a company site, a portfolio site, documentation, a single landing page, or a website with thousands of pages.

Hugo Features




Additional Features

See what's coming next in the Hugo roadmap.

The Benefits of Static Site Generators

The purpose of website generators is to render content into HTML files. Most are "dynamic site generators." That means the HTTP server---i.e., the program that sends files to the browser to be viewed---runs the generator to create a new HTML file every time an end user requests a page.

Over time, dynamic site generators were programmed to cache their HTML files to prevent unnecessary delays in delivering pages to end users. A cached page is a static version of a web page.

Hugo takes caching a step further and all HTML files are rendered on your computer. You can review the files locally before copying them to the computer hosting the HTTP server. Since the HTML files aren't generated dynamically, we say that Hugo is a static site generator.

This has many benefits. The most noticeable is performance. HTTP servers are very good at sending files---so good, in fact, that you can effectively serve the same number of pages with a fraction of the memory and CPU needed for a dynamic site.

More on Static Site Generators


To track Hugo's progress, see our GitHub Milestones.

In no particular order, here are some other features currently being worked on:

Contributions Welcome

Feel free to contribute to Hugo's development, improve Hugo's documentation, or open a new issue if you have an idea for a new feature.

Apache License

{{% note %}} Hugo v0.15 and later are released under the Apache 2.0 license. Earlier versions of Hugo were released under the Simple Public License. {{% /note %}}

Version 2.0, January 2004

Terms and Conditions for use, reproduction, and distribution

1. Definitions

“License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.

“Licensor” shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.

“Legal Entity” shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.

“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License.

“Source” form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.

“Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).

“Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.

“Contribution” shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as “Not a Contribution.”

“Contributor” shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.

2. Grant of Copyright License

Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.

3. Grant of Patent License

Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.

4. Redistribution

You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:

  • (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
  • (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
  • (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
  • (d) If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.

You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.

5. Submission of Contributions

Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.

6. Trademarks

This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty

Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.

8. Limitation of Liability

In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability

While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.


APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets [] replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives.

{{< code file="apache-notice.txt" download="apache-notice.txt" >}} Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. {{< /code >}}

Get Started

If this is your first time using Hugo and you've already installed Hugo on your machine, we recommend the quick start.

Quick Start

{{% note %}} This quick start uses macOS in the examples. For instructions about how to install Hugo on other operating systems, see install.

You also need Git installed to run this tutorial. {{% /note %}}

Step 1: Install Hugo

{{% note %}} Homebrew, a package manager for macOS, can be installed from See install if you are running Windows etc. {{% /note %}}

brew install hugo

To verify your new install:

hugo version

{{< asciicast HDlKrUrbfT7yiWsbd6QoxzRTN >}}

Step 2: Create a New Site

hugo new site quickstart

The above will create a new Hugo site in a folder named quickstart.

{{< asciicast 1PH9A2fs14Dnyarx5v8OMYQer >}}

Step 3: Add a Theme

See for a list of themes to consider. This quickstart uses the beautiful Ananke theme.

cd quickstart;\
git init;\
git submodule add themes/ananke;\

# Edit your config.toml configuration file
# and add the Ananke theme.
echo 'theme = "ananke"' >> config.toml

{{< asciicast WJM2LEZQs8VRhNeuZ5NiGPp9I >}}

Step 4: Add Some Content

hugo new posts/

Edit the newly created content file if you want. Now, start the Hugo server with drafts enabled:

▶ hugo server -D

Started building sites ...
Built site for language en:
1 of 1 draft rendered
0 future content
0 expired content
1 regular pages created
8 other pages created
0 non-page files copied
1 paginator pages created
0 categories created
0 tags created
total in 18 ms
Watching for changes in /Users/bep/sites/quickstart/{data,content,layouts,static,themes}
Serving pages from memory
Web Server is available at http://localhost:1313/ (bind address
Press Ctrl+C to stop

Navigate to your new site at http://localhost:1313/.

Step 5: Customize the Theme

Your new site already looks great, but you will want to tweak it a little before you release it to the public.

Site Configuration

Open up config.toml in a text editor:

baseURL = ""
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"

Replace the title above with something more personal. Also, if you already have a domain ready, set the baseURL. Note that this value is not needed when running the local development server.

{{% note %}} Tip: Make the changes to the site configuration or any other file in your site while the Hugo server is running, and you will see the changes in the browser right away. {{% /note %}}

For theme specific configuration options, see the theme site.

For further theme customization, see Customize a Theme.


{{< asciicast pWp4uvyAkdWgQllD9RCfeBL5k >}}

Install Hugo

{{% note %}} There is lots of talk about "Hugo being written in Go", but you don't need to install Go to enjoy Hugo. Just grab a precompiled binary! {{% /note %}}

Hugo is written in Go with support for multiple platforms. The latest release can be found at Hugo Releases.

Hugo currently provides pre-built binaries for the following:

  • macOS (Darwin) for x64, i386, and ARM architectures
  • Windows
  • Linux
  • FreeBSD

Hugo may also be compiled from source wherever the Go compiler tool chain can run; e.g., on other operating systems such as DragonFly BSD, OpenBSD, Plan 9, Solaris, and others. See for the full set of supported combinations of target operating systems and compilation architectures.

Quick Install

Binary (Cross-platform)

Download the appropriate version for your platform from Hugo Releases. Once downloaded, the binary can be run from anywhere. You don't need to install it into a global location. This works well for shared hosts and other systems where you don't have a privileged account.

Ideally, you should install it somewhere in your PATH for easy use. /usr/local/bin is the most probable location.

Homebrew (macOS)

If you are on macOS and using Homebrew, you can install Hugo with the following one-liner:

{{< code file="" >}} brew install hugo {{< /code >}}

For more detailed explanations, read the installation guides that follow for installing on macOS and Windows.

Chocolatey (Windows)

If you are on a Windows machine and use Chocolatey for package management, you can install Hugo with the following one-liner:

{{< code file="install-with-chocolatey.ps1" >}} choco install hugo -confirm {{< /code >}}


Prerequisite Tools

Vendored Dependencies

Hugo uses govendor to vendor dependencies, but we don't commit the vendored packages themselves to the Hugo git repository. Therefore, a simple go get is not supported because the command is not vendor aware. You must use govendor to fetch Hugo's dependencies.

Fetch from GitHub

{{< code file="" >}} go get govendor get go install {{< /code >}}

govendor get will fetch Hugo and all its dependent libraries to $GOPATH/src/, and go install compiles everything into a final hugo (or hugo.exe) executable inside $GOPATH/bin/.

{{% note %}} If you are a Windows user, substitute the $HOME environment variable above with %USERPROFILE%. {{% /note %}}



  1. You know how to open the macOS terminal.
  2. You're running a modern 64-bit Mac.
  3. You will use ~/Sites as the starting point for your site. (~/Sites is used for example purposes. If you are familiar enough with the command line and file system, you should have no issues following along with the instructions.)

Pick Your Method

There are three ways to install Hugo on your Mac

  1. The Homebrew brew utility
  2. Distribution (i.e., tarball)
  3. Building from Source

There is no "best" way to install Hugo on your Mac. You should use the method that works best for your use case.

Pros and Cons

There are pros and cons to each of the aforementioned methods:

  1. Homebrew. Homebrew is the simplest method and will require the least amount of work to maintain. The drawbacks aren't severe. The default package will be for the most recent release, so it will not have bug fixes until the next release (i.e., unless you install it with the --HEAD option). Hugo brew releases may lag a few days behind because it has to be coordinated with another team. Nevertheless, brew is the recommended installation method if you want to work from a stable, widely used source. Brew works well and is easy to update.

  2. Tarball. Downloading and installing from the tarball is also easy, although it requires a few more command line skills than does Homebrew. Updates are easy as well: you just repeat the process with the new binary. This gives you the flexibility to have multiple versions on your computer. If you don't want to use brew, then the tarball/binary is a good choice.

  3. Building from Source. Building from source is the most work. The advantage of building from source is that you don't have to wait for a release to add features or bug fixes. The disadvantage is that you need to spend more time managing the setup, which is manageable but requires more time than the preceding two options.

{{% note %}} Since building from source is appealing to more seasoned command line users, this guide will focus more on installing Hugo via Homebrew and Tarball. {{% /note %}}

Install Hugo with Brew

Step 1: Install brew if you haven't already

Go to the brew website,, and follow the directions there. The most important step is the installation from the command line:

{{< code file="" >}} ruby -e "$(curl -fsSL" {{< /code >}}

Step 2: Run the brew Command to Install hugo

Installing Hugo using brew is as easy as the following:

{{< code file="" >}} brew install hugo {{< /code >}}

If Homebrew is working properly, you should see something similar to the following:

==> Downloading
######################################################################### 100.0%
==> Pouring hugo-0.21.sierra.bottle.tar.gz
🍺  /usr/local/Cellar/hugo/0.21: 32 files, 17.4MB

{{% note "Installing the Latest Hugo with Brew" %}} Replace brew install hugo with brew install hugo --HEAD if you want the absolute latest in-development version. {{% /note %}}

brew should have updated your path to include Hugo. You can confirm by opening a new terminal window and running a few commands:

$ # show the location of the hugo executable
which hugo

# show the installed version
ls -l $( which hugo )
lrwxr-xr-x  1 mdhender admin  30 Mar 28 22:19 /usr/local/bin/hugo -> ../Cellar/hugo/0.13_1/bin/hugo

# verify that hugo runs correctly
hugo version
Hugo Static Site Generator v0.13 BuildDate: 2015-03-09T21:34:47-05:00

Install Hugo from Tarball

Step 1: Decide on the location

When installing from the tarball, you have to decide if you're going to install the binary in /usr/local/bin or in your home directory. There are three camps on this:

  1. Install it in /usr/local/bin so that all the users on your system have access to it. This is a good idea because it's a fairly standard place for executables. The downside is that you may need elevated privileges to put software into that location. Also, if there are multiple users on your system, they will all run the same version. Sometimes this can be an issue if you want to try out a new release.

  2. Install it in ~/bin so that only you can execute it. This is a good idea because it's easy to do, easy to maintain, and doesn't require elevated privileges. The downside is that only you can run Hugo. If there are other users on your site, they have to maintain their own copies. That can lead to people running different versions. Of course, this does make it easier for you to experiment with different releases.

  3. Install it in your Sites directory. This is not a bad idea if you have only one site that you're building. It keeps every thing in a single place. If you want to try out new releases, you can make a copy of the entire site and update the Hugo executable.

All three locations will work for you. In the interest of brevity, this guide focuses on option #2.

Step 2: Download the Tarball

  1. Open in your browser.

  2. Find the current release by scrolling down and looking for the green tag that reads "Latest Release."

  3. Download the current tarball for the Mac. The name will be something like hugo_X.Y_osx-64bit.tgz, where X.YY is the release number.

  4. By default, the tarball will be saved to your ~/Downloads directory. If you choose to use a different location, you'll need to change that in the following steps.

Step 3: Confirm your download

Verify that the tarball wasn't corrupted during the download:

tar tvf ~/Downloads/hugo_X.Y_osx-64bit.tgz
-rwxrwxrwx  0 0      0           0 Feb 22 04:02 hugo_X.Y_osx-64bit/hugo_X.Y_osx-64bit.tgz
-rwxrwxrwx  0 0      0           0 Feb 22 03:24 hugo_X.Y_osx-64bit/
-rwxrwxrwx  0 0      0           0 Jan 30 18:48 hugo_X.Y_osx-64bit/

The .md files are documentation for Hugo. The other file is the executable.

Step 4: Install Into Your bin Directory

# create the directory if needed
mkdir -p ~/bin

# make it the working directory
cd ~/bin

# extract the tarball
tar -xvzf ~/Downloads/hugo_X.Y_osx-64bit.tgz
Archive:  hugo_X.Y_osx-64bit.tgz
  x ./
  x ./hugo
  x ./
  x ./

# verify that it runs
./hugo version
Hugo Static Site Generator v0.13 BuildDate: 2015-02-22T04:02:30-06:00

You may need to add your bin directory to your PATH variable. The which command will check for us. If it can find hugo, it will print the full path to it. Otherwise, it will not print anything.

# check if hugo is in the path
which hugo

If hugo is not in your PATH, add it by updating your ~/.bash_profile file. First, start up an editor:

nano ~/.bash_profile

Add a line to update your PATH variable:

export PATH=$PATH:$HOME/bin

Then save the file by pressing Control-X, then Y to save the file and return to the prompt.

Close the terminal and open a new terminal to pick up the changes to your profile. Verify your success by running the which hugo command again.

You've successfully installed Hugo.

Build from Source on Mac

If you want to compile Hugo yourself, you'll need to install Go (aka Golang). You can install Go directly from the Go website or via Homebrew using the following command:

brew install go

Step 1: Get the Source

If you want to compile a specific version of Hugo, go to and download the source code for the version of your choice. If you want to compile Hugo with all the latest changes (which might include bugs), clone the Hugo repository:

git clone

{{% warning "Sometimes "Latest" = "Bugs""%}} Cloning the Hugo repository directly means taking the good with the bad. By using the bleeding-edge version of Hugo, you make your development susceptible to the latest features, as well as the latest bugs. Your feedback is appreciated. If you find a bug in the latest release, please create an issue on GitHub. {{% /warning %}}

Step 2: Compiling

Make the directory containing the source your working directory and then fetch Hugo's dependencies:

mkdir -p src/
ln -sf $(pwd) src/

# set the build path for Go
export GOPATH=$(pwd)

go get

This will fetch the absolute latest version of the dependencies. If Hugo fails to build, it may be the result of a dependency's author introducing a breaking change.

Once you have properly configured your directory, you can compile Hugo using the following command:

go build -o hugo main.go

Then place the hugo executable somewhere in your $PATH. You're now ready to start using Hugo.


The following aims to be a complete guide to installing Hugo on your Windows PC.


  1. You will use C:\Hugo\Sites as the starting point for your new project.
  2. You will use C:\Hugo\bin to store executable files.

Set up Your Directories

You'll need a place to store the Hugo executable, your content, and the generated Hugo website:

  1. Open Windows Explorer.
  2. Create a new folder: C:\Hugo, assuming you want Hugo on your C drive, although this can go anywhere
  3. Create a subfolder in the Hugo folder: C:\Hugo\bin
  4. Create another subfolder in Hugo: C:\Hugo\Sites

Technical Users

  1. Download the latest zipped Hugo executable from Hugo Releases.
  2. Extract all contents to your ..\Hugo\bin folder.
  3. The hugo executable will be named as hugo_hugo-version_platform_arch.exe. Rename the executable to hugo.exe for ease of use.
  4. In PowerShell or your preferred CLI, add the hugo.exe executable to your PATH by navigating to C:\Hugo\bin (or the location of your hugo.exe file) and use the command set PATH=%PATH%;C:\Hugo\bin. If the hugo command does not work after a reboot, you may have to run the command prompt as administrator.

Less-technical Users

  1. Go to the Hugo Releases page.
  2. The latest release is announced on top. Scroll to the bottom of the release announcement to see the downloads. They're all ZIP files.
  3. Find the Windows files near the bottom (they're in alphabetical order, so Windows is last) – download either the 32-bit or 64-bit file depending on whether you have 32-bit or 64-bit Windows. (If you don't know, see here.)
  4. Move the ZIP file into your C:\Hugo\bin folder.
  5. Double-click on the ZIP file and extract its contents. Be sure to extract the contents into the same C:\Hugo\bin folder – Windows will do this by default unless you tell it to extract somewhere else.
  6. You should now have three new files: hugo executable (e.g. hugo_0.18_windows_amd64.exe),, and (You can delete the ZIP download now.) Rename that hugo executable (hugo_hugo-version_platform_arch.exe) to hugo.exe for ease of use.

Now you need to add Hugo to your Windows PATH settings:

For Windows 10 Users:

  • Right click on the Start button.
  • Click on System.
  • Click on Advanced System Settings on the left.
  • Click on the Environment Variables... button on the bottom.
  • In the User variables section, find the row that starts with PATH (PATH will be all caps).
  • Double-click on PATH.
  • Click the New... button.
  • Type in the folder where hugo.exe was extracted, which is C:\Hugo\bin if you went by the instructions above. The PATH entry should be the folder where Hugo lives and not the binary. Press Enter when you're done typing.
  • Click OK at every window to exit.

{{% note "Path Editor in Windows 10"%}} The path editor in Windows 10 was added in the large November 2015 Update. You'll need to have that or a later update installed for the above steps to work. You can see what Windows 10 build you have by clicking on the  Start button → Settings → System → About. See here for more.) {{% /note %}}

For Windows 7 and 8.x users:

Windows 7 and 8.1 do not include the easy path editor included in Windows 10, so non-technical users on those platforms are advised to install a free third-party path editor like Windows Environment Variables Editor or Path Editor.

Verify the Executable

Run a few commands to verify that the executable is ready to run, and then build a sample site to get started.

1. Open a Command Prompt

At the prompt, type hugo help and press the Enter key. You should see output that starts with:

hugo is the main command, used to build your Hugo site.

Hugo is a Fast and Flexible Static Site Generator
built with love by spf13 and friends in Go.

Complete documentation is available at

If you do, then the installation is complete. If you don't, double-check the path that you placed the hugo.exe file in and that you typed that path correctly when you added it to your PATH variable. If you're still not getting the output, search the Hugo discussion forum to see if others have already figured out our problem. If not, add a note---in the "Support" category---and be sure to include your command and the output.

At the prompt, change your directory to the Sites directory.

C:\Program Files> cd C:\Hugo\Sites

2. Run the Command

Run the command to generate a new site. I'm using as the name of the site.

C:\Hugo\Sites> hugo new site

You should now have a directory at C:\Hugo\Sites\ Change into that directory and list the contents. You should get output similar to the following:

&nbsp;Directory of C:\hugo\sites\
04/13/2015  10:44 PM    <DIR>          .
04/13/2015  10:44 PM    <DIR>          ..
04/13/2015  10:44 PM    <DIR>          archetypes
04/13/2015  10:44 PM                83 config.toml
04/13/2015  10:44 PM    <DIR>          content
04/13/2015  10:44 PM    <DIR>          data
04/13/2015  10:44 PM    <DIR>          layouts
04/13/2015  10:44 PM    <DIR>          static
               1 File(s)             83 bytes
               7 Dir(s)   6,273,331,200 bytes free

Troubleshoot Windows Installation

@dhersam has created a nice video on common issues:

{{< youtube c8fJIRNChmU >}}


Snap Package

In any of the Linux distributions that support snaps:

snap install hugo

{{% note %}} Hugo-as-a-snap can write only inside the user’s $HOME directory---and gvfs-mounted directories owned by the user---because of Snaps’ confinement and security model. More information is also available in this related GitHub issue. {{% /note %}}

Debian and Ubuntu

Debian and Ubuntu provide a hugo version via apt-get:

sudo apt-get install hugo


  • Native Debian/Ubuntu package maintained by Debian Developers
  • Pre-installed bash completion script and man pages


  • Might not be the latest version, especially if you are using an older, stable version (e.g., Ubuntu 16.04 LTS). Until backports and PPA are available, you may consider installing the Hugo snap package to get the latest version of Hugo.


You can also install Hugo from the Arch user repository on Arch Linux or derivatives such as Manjaro.

Be aware that Hugo is built from source. This means that additional tools like Git and Go will be installed as well.

sudo pacman -S yaourt
yaourt -S hugo

Fedora, CentOS, and Red Hat

See the related discussion in the Hugo forums.

Upgrade Hugo

Upgrading Hugo is as easy as downloading and replacing the executable you’ve placed in your PATH.

Install Pygments (Optional)

The Hugo executable has one optional external dependency for source code highlighting (Pygments).

If you want to have source code highlighting using the highlight shortcode, you need to install the Python-based Pygments program. The procedure is outlined on the Pygments homepage.

Next Steps

Now that you've installed Hugo, read the Quick Start guide and explore the rest of the documentation. If you have questions, ask the Hugo community directly by visiting the Hugo Discussion Forum.

Basic Usage

The following is a description of the most common commands you will use while developing your Hugo project. See the Command Line Reference for a comprehensive view of Hugo's CLI.

Test Installation

Once you have installed Hugo, make sure it is in your PATH. You can test that Hugo has been installed correctly via the help command:

hugo help

The output you see in your console should be similar to the following:

hugo is the main command, used to build your Hugo site.

Hugo is a Fast and Flexible Static Site Generator
built with love by spf13 and friends in Go.

Complete documentation is available at

  hugo [flags]
  hugo [command]

Available Commands:
  benchmark   Benchmark Hugo by building a site a number of times.
  check       Contains some verification checks
  config      Print the site configuration
  convert     Convert your content to different formats
  env         Print Hugo version and environment info
  gen         A collection of several useful generators.
  help        Help about any command
  import      Import your site from others.
  list        Listing out various types of content
  new         Create new content for your site
  server      A high performance webserver
  undraft     Undraft changes the content's draft status from 'True' to 'False'
  version     Print the version number of Hugo

  -b, --baseURL string             hostname (and path) to the root, e.g.
  -D, --buildDrafts                include content marked as draft
  -E, --buildExpired               include expired content
  -F, --buildFuture                include content with publishdate in the future
      --cacheDir string            filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
      --canonifyURLs               if true, all relative URLs will be canonicalized using baseURL
      --cleanDestinationDir        remove files from destination not found in static directories
      --config string              config file (default is path/config.yaml|json|toml)
  -c, --contentDir string          filesystem path to content directory
  -d, --destination string         filesystem path to write files to
      --disable404                 do not render 404 page
      --disableKinds stringSlice   disable different kind of pages (home, RSS etc.)
      --disableRSS                 do not build RSS files
      --disableSitemap             do not build Sitemap file
      --enableGitInfo              add Git revision, date and author info to the pages
      --forceSyncStatic            copy all files when static is changed.
  -h, --help                       help for hugo
      --i18n-warnings              print missing translations
      --ignoreCache                ignores the cache directory
  -l, --layoutDir string           filesystem path to layout directory
      --log                        enable Logging
      --logFile string             log File path (if set, logging enabled automatically)
      --noChmod                    don't sync permission mode of files
      --noTimes                    don't sync modification time of files
      --pluralizeListTitles        pluralize titles in lists using inflect (default true)
      --preserveTaxonomyNames      preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
      --quiet                      build in quiet mode
      --renderToMemory             render to memory (only useful for benchmark testing)
  -s, --source string              filesystem path to read files relative from
      --stepAnalysis               display memory and timing of different steps of the program
  -t, --theme string               theme to use (located in /themes/THEMENAME/)
      --themesDir string           filesystem path to themes directory
      --uglyURLs                   if true, use /filename.html instead of /filename/
  -v, --verbose                    verbose output
      --verboseLog                 verbose logging
  -w, --watch                      watch filesystem for changes and recreate as needed

The hugo Command

The most common usage is probably to run hugo with your current directory being the input directory.

This generates your website to the public/ directory by default, although you can customize the output directory in your site configuration by changing the publishDir field.

The site Hugo renders into public/ is ready to be deployed to your web server:

0 draft content
0 future content
99 pages created
0 paginator pages created
16 tags created
0 groups created
in 90 ms

Draft, Future, and Expired Content

Hugo allows you to set draft, publishdate, and even expirydate in your content's front matter. By default, Hugo will not publish:

  1. Content with a future publishdate value
  2. Content with draft: true status
  3. Content with a past expirydate value

All three of these can be overridden during both local development and deployment by adding the following flags to hugo and hugo server, respectively, or by changing the boolean values assigned to the fields of the same name (without --) in your configuration:

  1. --buildFuture
  2. --buildDrafts
  3. --buildExpired


Hugo comes with LiveReload built in. There are no additional packages to install. A common way to use Hugo while developing a site is to have Hugo run a server with the hugo server command and watch for changes:

hugo server
0 draft content
0 future content
99 pages created
0 paginator pages created
16 tags created
0 groups created
in 120 ms
Watching for changes in /Users/yourname/sites/yourhugosite/{data,content,layouts,static}
Serving pages from /Users/yourname/sites/yourhugosite/public
Web Server is available at http://localhost:1313/
Press Ctrl+C to stop

This will run a fully functioning web server while simultaneously watching your file system for additions, deletions, or changes within the following areas of your project organization:

  • /static/*
  • /content/*
  • /data/*
  • /i18n/*
  • /layouts/*
  • /themes/<CURRENT-THEME>/*
  • config

Whenever you make changes, Hugo will simultaneously rebuild the site and continue to serve content. As soon as the build is finished, LiveReload tells the browser to silently reload the page.

Most Hugo builds are so fast that you may not notice the change unless looking directly at the site in your browser. This means that keeping the site open on a second monitor (or another half of your current monitor) allows you to see the most up-to-date version of your website without the need to leave your text editor.

{{% note "Closing </body> Tag"%}} Hugo injects the LiveReload <script> before the closing </body> in your templates and will therefore not work if this tag is not present.. {{% /note %}}

Disable LiveReload

LiveReload works by injecting JavaScript into the pages Hugo generates. The script creates a connection from the browser's web socket client to the Hugo web socket server.

LiveReload is awesome for development. However, some Hugo users may use hugo server in production to instantly display updated content. The following methods make it easy to disable LiveReload:

hugo server --watch=false


hugo server --disableLiveReload

The latter flag can be omitted by adding the following key-value to your config.toml or config.yml file, respectively:

disableLiveReload = true
disableLiveReload: true

Deploy Your Website

After running hugo server for local web development, you need to do a final hugo run without the server part of the command to rebuild your site. You may then deploy your site by copying the public/ directory to your production web server.

Since Hugo generates a static website, your site can be hosted anywhere using any web server. See Hosting and Deployment for methods for hosting and automating deployments contributed by the Hugo community.

{{% warning "Generated Files are NOT Removed on Site Build" %}} Running hugo does not remove generated files before building. This means that you should delete your public/ directory (or the publish directory you specified via flag or configuration file) before running the hugo command. If you do not remove these files, you run the risk of the wrong files (e.g., drafts or future posts) being left in the generated site. {{% /warning %}}

Dev vs Deploy Destinations

Hugo does not remove generated files before building. An easy workaround is to use different directories for development and production.

To start a server that builds draft content (helpful for editing), you can specify a different destination; e.g., a dev/ directory:

hugo server -wDs ~/Code/hugo/docs -d dev

When the content is ready for publishing, use the default public/ dir:

hugo -s ~/Code/hugo/docs

This prevents draft content from accidentally becoming available.

Directory Structure

New Site Scaffolding

Running the hugo new site generator from the command line will create a directory structure with the following elements:

├── archetypes
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes

Directory Structure Explained

The following is a high-level overview of each of the directories with links to each of their respective sections with in the Hugo docs.

archetypes : You can create new content files in Hugo using the hugo new command. By default, hugo will create new content files with at least date, title (inferred from the file name), and draft = true. This saves time and promotes consistency for sites using multiple content types. You can create your own archetypes with custom preconfigured front matter fields as well.

config.toml : Every Hugo project should have a configuration file in TOML, YAML, or JSON format at the root. Many sites may need little to no configuration, but Hugo ships with a large number of configuration directives for more granular directions on how you want Hugo to build your website.

content : All content for your website will live inside this directory. Each top-level folder in Hugo is considered a content section. For example, if your site has three main sections---blog, articles, and tutorials---you will have three directories at content/blog, content/articles, and content/tutorials. Hugo uses sections to assign default content types.

data : This directory is used to store configuration files that can be used by Hugo when generating your website. You can write these files in YAML, JSON, or TOML format. In addition to the files you add to this folder, you can also create data templates that pull from dynamic content.

layouts : Stores templates in the form of .html files that specify how views of your content will be rendered into a static website. Templates include list pages, your homepage, taxonomy templates, partials, single page templates, and more.

static : stores all the static content for your future website: images, CSS, JavaScript, etc. When Hugo builds your site, all assets inside your static directory are copied over as-is. A good example of using the static folder is for verifying site ownership on Google Search Console, where you want Hugo to copy over a complete HTML file without modifying its content.

{{% note %}} Hugo does not currently ship with an asset pipeline (#3207). You can solicit support from the community in the Hugo forums or check out a few of the Hugo starter kits for examples of how Hugo developers are managing static assets. {{% /note %}}

Configure Hugo

The directory structure of a Hugo website—or more precisely, the source organization of files containing the website's content and templates—provides most of the configuration information that Hugo needs in order to generate a finished website.

Because of Hugo's sensible defaults, many websites may not need a configuration file. Hugo is designed to recognize certain typical usage patterns.

Configuration Lookup Order

Similar to the template lookup order, Hugo has a default set of rules for searching for a configuration file in the root of your website's source directory as a default behavior:

  1. ./config.toml
  2. ./config.yaml
  3. ./config.json

In your config file, you can direct Hugo as to how you want your website rendered, control your website's menus, and arbitrarily define site-wide parameters specific to your project.

YAML Configuration

The following is a typical example of a YAML configuration file. Note the document opens with 3 hyphens and closes with 3 periods. The values nested under params: will populate the .Site.Params variable for use in templates:

{{< code file="config.yml">}}

baseURL: "" title: "My Hugo Site" footnoteReturnLinkContents: "↩" permalinks: post: /:year/:month/:title/ params: Subtitle: "Hugo is Absurdly Fast!" AuthorName: "Jon Doe" GitHubUser: "spf13" ListOfFoo: - "foo1" - "foo2" SidebarRecentLimit: 5 ... {{< /code >}}

All Variables, YAML

The following is the full list of Hugo-defined variables in an example YAML file. The values provided in this example represent the default values used by Hugo.

{{< code file="config.yml" download="config.yml" >}}

archetypeDir: "archetypes"

hostname (and path) to the root, e.g.

baseURL: ""

include content marked as draft

buildDrafts: false

include content with publishdate in the future

buildFuture: false

include content already expired

buildExpired: false

enable this to make all relative URLs relative to content root. Note that this does not affect absolute URLs. See the "URL Management" page

relativeURLs: false canonifyURLs: false

config file (default is path/config.yaml|json|toml)

config: "config.toml" contentDir: "content" dataDir: "data" defaultExtension: "html" defaultLayout: "post"

Missing translations will default to this content language

defaultContentLanguage: "en"

Renders the default content language in subdir, e.g. /en/. The root directory / will redirect to /en/

defaultContentLanguageInSubdir: false disableLiveReload: false

Do not build RSS files

disableRSS: false

Do not build Sitemap file

disableSitemap: false

Enable GitInfo feature

enableGitInfo: false

Build robots.txt file

enableRobotsTXT: false

Do not render 404 page

disable404: false

Do not inject generator meta tag on homepage

disableHugoGeneratorInject: false

Allows you to disable all page types and will render nothing related to 'kind';

values = "page", "home", "section", "taxonomy", "taxonomyTerm", "RSS", "sitemap", "robotsTXT", "404"

disableKinds: []

Do not make the url/path to lowercase

disablePathToLower: false ""

Enable Emoji emoticons support for page content; see

enableEmoji: false

Show a placeholder instead of the default value or an empty string if a translation is missing

enableMissingTranslationPlaceholders: false footnoteAnchorPrefix: "" footnoteReturnLinkContents: ""

google analytics tracking id

googleAnalytics: ""

if true, auto-detect Chinese/Japanese/Korean Languages in the content. (.Summary and .WordCount can work properly in CJKLanguage)

hasCJKLanguage: false languageCode: "" layoutDir: "layouts"

Enable Logging

log: false

Log File path (if set, logging enabled automatically)

logFile: ""

"toml","yaml", or "json"

metaDataFormat: "toml" newContentEditor: ""

Don't sync permission mode of files

noChmod: false

Don't sync modification time of files

noTimes: false


paginate: 10 paginatePath: "page"

See "content-management/permalinks"


Pluralize titles in lists using inflect

pluralizeListTitles: true

Preserve special characters in taxonomy names ("Gérard Depardieu" vs "Gerard Depardieu")

preserveTaxonomyNames: false

filesystem path to write files to

publishDir: "public"

enables syntax guessing for code fences without specified language

pygmentsCodeFencesGuessSyntax: false

color-codes for highlighting derived from this style

pygmentsStyle: "monokai"

true use pygments-css or false will color code directly

pygmentsUseClasses: false

maximum number of items in the RSS feed

rssLimit: 15

see "Section Menu for Lazy Bloggers", /templates/menu-templates for more info

SectionPagesMenu: ""

default sitemap configuration map


filesystem path to read files relative from

source: "" staticDir: "static"

display memory and timing of different steps of the program

stepAnalysis: false

theme to use (located by default in /themes/THEMENAME/)

themesDir: "themes" theme: "" title: ""

if true, use /filename.html instead of /filename/

uglyURLs: false

verbose output

verbose: false

verbose logging

verboseLog: false

watch filesystem for changes and recreate as needed

watch: true taxonomies:

  • category: "categories"
  • tag: "tags"

{{< /code >}}

TOML Configuration

The following is an example of a TOML configuration file. The values under [params] will populate the .Site.Params variable for use in templates:

contentDir = "content"
layoutDir = "layouts"
publishDir = "public"
buildDrafts = false
baseURL = ""
canonifyURLs = true
title = "My Hugo Site"

  category = "categories"
  tag = "tags"

  subtitle = "Hugo is Absurdly Fast!"
  author = "John Doe"

All Variables, TOML

The following is the full list of Hugo-defined variables in an example TOML file. The values provided in this example represent the default values used by Hugo.

{{< code file="config.toml" download="config.toml">}} +++ archetypeDir = "archetypes"

hostname (and path) to the root, e.g.

baseURL = ""

include content marked as draft

buildDrafts = false

include content with publishdate in the future

buildFuture = false

include content already expired

buildExpired = false

enable this to make all relative URLs relative to content root. Note that this does not affect absolute URLs.

relativeURLs = false canonifyURLs = false

config file (default is path/config.yaml|json|toml)

config = "config.toml" contentDir = "content" dataDir = "data" defaultExtension = "html" defaultLayout = "post"

Missing translations will default to this content language

defaultContentLanguage = "en"

Renders the default content language in subdir, e.g. /en/. The root directory / will redirect to /en/

defaultContentLanguageInSubdir = false disableLiveReload = false

Do not build RSS files

disableRSS = false

Do not build Sitemap file

disableSitemap = false

Enable GitInfo feature

enableGitInfo = false

Build robots.txt file

enableRobotsTXT = false

Do not render 404 page

disable404 = false

Do not inject generator meta tag on homepage

disableHugoGeneratorInject = false

Allows you to disable all page types and will render nothing related to 'kind';

values = "page", "home", "section", "taxonomy", "taxonomyTerm", "RSS", "sitemap", "robotsTXT", "404"

disableKinds = []

Do not make the url/path to lowercase

disablePathToLower = false

Enable Emoji emoticons support for page content; see

enableEmoji = false

Show a placeholder instead of the default value or an empty string if a translation is missing

enableMissingTranslationPlaceholders = false footnoteAnchorPrefix = "" footnoteReturnLinkContents = ""

google analytics tracking id

googleAnalytics = ""

if true, auto-detect Chinese/Japanese/Korean Languages in the content. (.Summary and .WordCount can work properly in CJKLanguage)

hasCJKLanguage = false languageCode = "" layoutDir = "layouts"

Enable Logging

log = false

Log File path (if set, logging enabled automatically)

logFile =

maximum number of items in the RSS feed

rssLimit = 15

"toml","yaml", or "json"

metaDataFormat = "toml" newContentEditor = ""

Don't sync permission mode of files

noChmod = false

Don't sync modification time of files

noTimes = false


paginate = 10 paginatePath = "page"

See "content-management/permalinks"

permalinks =

Pluralize titles in lists using inflect

pluralizeListTitles = true

Preserve special characters in taxonomy names ("Gérard Depardieu" vs "Gerard Depardieu")

preserveTaxonomyNames = false

filesystem path to write files to

publishDir = "public"

enables syntax guessing for code fences without specified language

pygmentsCodeFencesGuessSyntax = false

color-codes for highlighting derived from this style

pygmentsStyle = "monokai"

true: use pygments-css or false: color-codes directly

pygmentsUseClasses = false

see "Section Menu for Lazy Bloggers", /templates/menu-templates for more info

SectionPagesMenu =

default sitemap configuration map

sitemap =

filesystem path to read files relative from

source = "" staticDir = "static"

display memory and timing of different steps of the program

stepAnalysis = false

theme to use (located by default in /themes/THEMENAME/)

themesDir = "themes" theme = "" title = ""

if true, use /filename.html instead of /filename/

uglyURLs = false

verbose output

verbose = false

verbose logging

verboseLog = false

watch filesystem for changes and recreate as needed

watch = true taxonomies category = "categories" tag = "tags" +++ {{< /code >}}

{{% note %}} If you are developing your site on a *nix machine, here is a handy shortcut for finding a configuration option from the command line:

hugo config | grep emoji
enableemoji: true

{{% /note %}}

Environmental Variables

In addition to the 3 config options already mentioned, configuration key-values can be defined through operating system environment variables.

For example, the following command will effectively set a website's title on Unix-like systems:

$ env HUGO_TITLE="Some Title" hugo

{{% note "Setting Environment Variables" %}} Names must be prefixed with HUGO_ and the configuration key must be set in uppercase when setting operating system environment variables. {{% /note %}}

Ignore Files When Rendering

The following statement inside ./config.toml will cause Hugo to ignore files ending with .foo and .boo when rendering:

ignoreFiles = [ "\\.foo$", "\\.boo$" ]

The above is a list of regular expressions. Note that the backslash (\) character is escaped in this example to keep TOML happy.

Configure Blackfriday

Blackfriday is Hugo's built-in Markdown rendering engine.

Hugo typically configures Blackfriday with sane default values that should fit most use cases reasonably well.

However, if you have specific needs with respect to Markdown, Hugo exposes some of its Blackfriday behavior options for you to alter. The following table lists these Hugo options, paired with the corresponding flags from Blackfriday's source code ( html.go and markdown.go).

{{< readfile file="/content/readfiles/" markdown="true" >}}

{{% note %}}

  1. Blackfriday flags are case sensitive as of Hugo v0.15.
  2. Blackfriday flags must be grouped under the blackfriday key and can be set on both the site level and the page level. Any setting on a page will override its respective site setting. {{% /note %}}

{{< code file="bf-config.toml" >}} blackfriday angledQuotes = true fractions = false plainIDAnchors = true extensions = ["hardLineBreak"] {{< /code >}}

{{< code file="bf-config.yml" >}} blackfriday: angledQuotes: true fractions: false plainIDAnchors: true extensions: - hardLineBreak {{< /code >}}

Configure Additional Output Formats

Hugo v0.20 introduced the ability to render your content to multiple output formats (e.g., to JSON, AMP html, or CSV). See Output Formats for information on how to add these values to your Hugo project's configuration file.

Configuration Format Specs



Hugo provides a robust theming system that is easy to implement yet feature complete. You can view the themes created by the Hugo community on the Hugo themes website.

Hugo themes are powered by the excellent Go template library and are designed to reduce code duplication. They are easy to both customize and keep in synch with the upstream theme.

Install and Use Themes

{{% note "No Default Theme" %}} Hugo currently doesn’t ship with a “default” theme. This decision is intentional. We leave it up to you to decide which theme best suits your Hugo project. {{% /note %}}


  1. You have already installed Hugo on your development machine.
  2. You have git installed on your machine and you are familiar with basic git usage.

Install Themes

The community-contributed themes featured on are hosted in a [centralized GitHub repository][themesrepo]. The Hugo Themes Repo at is really a meta repository that contains pointers to a set of contributed themes.

{{% warning "Get git First" %}} Without Git installed on your computer, none of the following theme instructions will work. Git tutorials are beyond the scope of the Hugo docs, but GitHub and codecademy offer free, interactive courses for beginners. {{% /warning %}}

Install All Themes

You can install all available Hugo themes by cloning the entire [Hugo Theme repository on GitHub][themesrepo] from within your working directory. Depending on your internet connection the download of all themes might take a while.

git clone --depth 1 --recursive themes

Before you use a theme, remove the .git folder in that theme's root folder. Otherwise, this will cause problem if you deploy using Git.

Install a Single Theme

Change into the themes directory and download a theme by replacing URL_TO_THEME with the URL of the theme repository:

cd themes
git clone URL_TO_THEME

The following example shows how to use the "Hyde" theme, which has its source hosted at

{{< code file="" >}} cd themes git clone {{< /code >}}

Alternatively, you can download the theme as a .zip file, unzip the theme contents, and then move the unzipped source into your themes directory.

{{% note "Read the README" %}} Always review the file that is shipped with a theme. Often, these files contain further instructions required for theme setup; e.g., copying values from an example configuration file. {{% /note %}}

Theme Placement

Please make certain you have installed the themes you want to use in the /themes directory. This is the default directory used by Hugo. Hugo comes with the ability to change the themes directory via the themesDir variable in your site configuration, but this is not recommended.

Use Themes

Hugo applies the decided theme first and then applies anything that is in the local directory. This allows for easier customization while retaining compatibility with the upstream version of the theme. To learn more, go to customizing themes.

Command Line

There are two different approaches to using a theme with your Hugo website: via the Hugo CLI or as part of your

To change a theme via the Hugo CLI, you can pass the -t flag when building your site:

hugo -t themename

Likely, you will want to add the theme when running the Hugo local server, especially if you are going to customize the theme:

hugo server -t themename

config File

If you've already decided on the theme for your site and do not want to fiddle with the command line, you can add the theme directly to your site configuration file:

theme: themename

{{% note "A Note on themename" %}} The themename in the above examples must match the name of the specific theme directory inside /themes; i.e., the directory name (likely lowercase and urlized) rather than the name of the theme displayed in the Themes Showcase site. {{% /note %}}


Customize a Theme

The following are key concepts for Hugo site customization with themes. Hugo permits you to supplement or override any theme template or static file with files in your working directory.

{{% note %}} When you use a theme cloned from its git repository, do not edit the theme's files directly. Instead, theme customization in Hugo is a matter of overriding the templates made available to you in a theme. This provides the added flexibility of tweaking a theme to meet your needs while staying current with a theme's upstream. {{% /note %}}

Override Static Files

There are times where you want to include static assets that differ from versions of the same asset that ships with a theme.

For example, a theme may use jQuery 1.8 in the following location:


You want to replace the version of jQuery that ships with the theme with the newer jquery-3.1.1.js. The easiest way to do this is to replace the file with a file of the same name in the same relative path in your project's root. Therefore, change jquery-3.1.1.js to jquery.min.js so that it is identical to the theme's version and place the file here:


Override Template Files

Anytime Hugo looks for a matching template, it will first check the working directory before looking in the theme directory. If you would like to modify a template, simply create that template in your local layouts directory.

The template lookup order explains the rules Hugo uses to determine which template to use for a given piece of content. Read and understand these rules carefully.

This is especially helpful when the theme creator used partial templates. These partial templates are perfect for easy injection into the theme with minimal maintenance to ensure future compatibility.

For example:


Would be overwritten by


{{% warning %}} This only works for templates that Hugo "knows about" (i.e., that follow its convention for folder structure and naming). If a theme imports template files in a creatively named directory, Hugo won’t know to look for the local /layouts first. {{% /warning %}}

Override Archetypes

If the archetype that ships with the theme for a given content type (or all content types) doesn’t fit with how you are using the theme, feel free to copy it to your /archetypes directory and make modifications as you see fit.

{{% warning "Beware of layouts/_default" %}} The _default directory is a very powerful force in Hugo, especially as it pertains to overwriting theme files. If a default file is located in the local archetypes or layout directory (i.e., archetypes/ or /layouts/_default/*.html, respectively), it will override the file of the same name in the corresponding theme directory (i.e., themes/<THEME>/archetypes/ or themes/<THEME>/layout/_defaults/*.html, respectively).

It is usually better to override specific files; i.e. rather than using layouts/_default/*.html in your working directory. {{% /warning %}}

partials: /templates/partials/

Create a Theme

{{% warning "Use Relative Links" %}} If you're creating a theme with plans to share it with the community, use relative URLs since users of your theme may not publish from the root of their website. See relURL and absURL. {{% /warning %}}

Hugo can initialize a new blank theme directory within your existing themes using the hugo new command:

hugo new theme [name]

Theme Components

A theme consists of templates and static assets such as javascript and css files. Themes can also provide archetypes, which are archetypal content types used by the hugo new command to scaffold new content files with preconfigured front matter.

{{% note "Use the Hugo Generator Tag" %}} The .Hugo.Generator tag is included in all themes featured in the Hugo Themes Showcase. We ask that you include the generator tag in all sites and themes you create with Hugo to help the core team track Hugo's usage and popularity. {{% /note %}}


Hugo is built around the concept that things should be as simple as possible. Fundamentally, website content is displayed in two different ways, a single piece of content and a list of content items. With Hugo, a theme layout starts with the defaults. As additional layouts are defined, they are used for the content type or section they apply to. This keeps layouts simple, but permits a large amount of flexibility.

Single Content

The default single file layout is located at layouts/_default/single.html.

List of Contents

The default list file layout is located at layouts/_default/list.html.

Partial Templates

Theme creators should liberally use partial templates throughout their theme files. Not only is a good DRY practice to include shared code, but partials are a special template type that enables the themes end user to be able to overwrite just a small piece of a file or inject code into the theme from their local /layouts. These partial templates are perfect for easy injection into the theme with minimal maintenance to ensure future compatibility.


Everything in the static directory will be copied directly into the final site when rendered. No structure is provided here to enable complete freedom. It is common to organize the static content into:


The actual structure is entirely up to you, the theme creator, on how you would like to organize your files.


If your theme makes use of specific keys in the front matter, it is a good idea to provide an archetype for each content type you have. Read more about archetypes.

Content Management

A static site generator needs to extend beyond front matter and a couple templates to be both scalable and manageable. Hugo was designed with not only developers in mind, but also content managers and authors.

Content Organization

{{% note %}} This section is not updated with the new nested sections support in Hugo 0.24, see {{% /note %}} {{% todo %}} See above {{% /todo %}}

Organization of Content Source

In Hugo, your content should be organized in a manner that reflects the rendered website.

While Hugo supports content nested at any level, the top levels (i.e. content/<DIRECTORIES>) are special in Hugo and are considered the content sections. Without any additional configuration, the following will just work:

└── content
    └── about
    |   └──  // <-
    ├── post
    |   ├──   // <-
    |   ├── happy
    |   |   └──  // <-
    |   └──  // <-
    └── quote
        ├──       // <-
        └──      // <-

Path Breakdown in Hugo

The following demonstrates the relationships between your content organization and the output URL structure for your Hugo website when it renders. These examples assume you are using pretty URLs, which is the default behavior for Hugo. The examples also assume a key-value of baseurl = "" in your site's configuration file.

Index Pages: has a special role in Hugo. It allows you to add front matter and content to your list templates as of v0.18. These templates include those for section templates, taxonomy templates, taxonomy terms templates, and your homepage template. In your templates, you can grab information from using the .Site.GetPage function.

You can keep one for your homepage and one in each of your content sections, taxonomies, and taxonomy terms. The following shows typical placement of an that would contain content and front matter for a posts section list page on a Hugo website:

.         url
.       ⊢--^-⊣
.        path    slug
.       ⊢--^-⊣⊢---^---⊣
.           filepath
.       ⊢------^------⊣

At build, this will output to the following destination with the associated values:

                     url ("/posts/")
       baseurl      section ("posts")

Single Pages in Sections

Single content files in each of your sections are going to be rendered as single page templates. Here is an example of a single post within posts:

                   path ("posts/")
.       ⊢-----------^------------⊣
.      section        slug
.       ⊢-^-⊣⊢--------^----------⊣

At the time Hugo builds your site, the content will be output to the following destination:

                               url ("/posts/my-first-hugo-post/")
       baseurl     section     slug

Section with Nested Directories

To continue the example, the following demonstrates destination paths for a file located at content/events/chicago/ in the same site:


      baseURL             path        slug
⊢--------^--------⊣ ⊢------^-----⊣⊢----^------⊣

{{% note %}} As of v0.20, Hugo does not recognize nested sections. While you can nest as many content directories as you'd like, any child directory of a section will still be considered the same section as that of its parents. Therefore, in the above example, {{.Section}} for is events and not chicago. See the related issue on GitHub. {{% /note %}}

Paths Explained

The following concepts will provide more insight into the relationship between your project's organization and the default behaviors of Hugo when building the output website.


A default content type is determined by a piece of content's section. section is determined by the location within the project's content directory. section cannot be specified or overridden in front matter.


A content's slug is either name.extension or name/. The value for slug is determined by

  • the name of the content file (e.g., OR
  • front matter overrides


A content's path is determined by the section's path to the file. The file path

  • is based on the path to the content's location AND
  • does not include the slug


The url is the relative URL for the piece of content. The url

  • is based on the content's location within the directory structure OR
  • is defined in front matter and overrides all the above

Override Destination Paths via Front Matter

Hugo believes that you organize your content with a purpose. The same structure that works to organize your source content is used to organize the rendered site. As displayed above, the organization of the source content will be mirrored in the destination.

There are times where you may need more control over your content. In these cases, there are fields that can be specified in the front matter to determine the destination of a specific piece of content.

The following items are defined in this order for a specific reason: items explained further down in the list will override earlier items, and not all of these items can be defined in front matter:


This isn't in the front matter, but is the actual name of the file minus the extension. This will be the name of the file in the destination (e.g., content/posts/ becomes


When defined in the front matter, the slug can take the place of the filename for the destination.

{{< code file="content/posts/" >}}

title: New Post slug: "new-post"

{{< /code >}}

This will render to the following destination according to Hugo's default behavior:


section is determined by a content's location on disk and cannot be specified in the front matter. See sections for more information.


A content's type is also determined by its location on disk but, unlike section, it can be specified in the front matter. See types. This can come in especially handy when you want a piece of content to render using a different layout. In the following example, you can create a layout at layouts/new/mylayout.html that Hugo will use to render this piece of content, even in the midst of many other posts.

{{< code file="content/posts/" >}}

title: My Post type: new layout: mylayout

{{< /code >}}


A complete URL can be provided. This will override all the above as it pertains to the end destination. This must be the path from the baseURL (starting with a /). url will be used exactly as it provided in the front matter and will ignore the --uglyURLs setting in your site configuration:

{{< code file="content/posts/" >}}

title: Old URL url: /blog/new-url/

{{< /code >}}

Assuming your baseURL is configured to, the addition of url to the front matter will make render to the following destination:

You can see more information on how to control output paths in URL Management.

Supported Content Formats

Markdown is the main content format and comes in two flavours: The excellent Blackfriday project (name your files *.md or set markup = "markdown" in front matter) or its fork Mmark (name your files *.mmark or set markup = "mmark" in front matter), both very fast markdown engines written in Go.

For Emacs users, goorgeous provides built-in native support for Org-mode (name your files *.org or set markup = "org" in front matter)

{{% note "Deeply Nested Lists" %}} Before you begin writing your content in markdown, Blackfriday has a known issue (#329) with handling deeply nested lists. Luckily, there is an easy workaround. Use 4-spaces (i.e., tab) rather than 2-space indentations. {{% /note %}}

Configure BlackFriday Markdown Rendering

You can configure multiple aspects of Blackfriday as show in the following list. See the docs on Configuration for the full list of explicit directions you can give to Hugo when rendering your site.

{{< readfile file="/content/readfiles/" markdown="true" >}}

Extend Markdown

Hugo provides some convenient methods for extending markdown.

Task Lists

Hugo supports GitHub-styled task lists (i.e., TODO lists) for the Blackfriday markdown renderer. If you do not want to use this feature, you can disable it in your configuration.

Example Task List Input

{{< code file="content/" >}}

  • a task list item
  • list syntax required
  • incomplete
  • completed {{< /code >}}

Example Task List Output

The preceding markdown produces the following HTML in your rendered website:

<ul class="task-list">
    <li><input type="checkbox" disabled="" class="task-list-item"> a task list item</li>
    <li><input type="checkbox" disabled="" class="task-list-item"> list syntax required</li>
    <li><input type="checkbox" disabled="" class="task-list-item"> incomplete</li>
    <li><input type="checkbox" checked="" disabled="" class="task-list-item"> completed</li>

Example Task List Display

The following shows how the example task list will look to the end users of your website. Note that visual styling of lists is up to you. This list has been styled according to the Hugo Docs stylesheet.

  • a task list item
  • list syntax required
  • incomplete
  • completed


To add emojis directly to content, set enableEmoji to true in your site configuration. To use emojis in templates or shortcodes, see emojify function.

For a full list of emojis, see the Emoji cheat sheet.


If you write in Markdown and find yourself frequently embedding your content with raw HTML, Hugo provides built-in shortcodes functionality. This is one of the most powerful features in Hugo and allows you to create your own Markdown extensions very quickly.

See Shortcodes for usage, particularly for the built-in shortcodes that ship with Hugo, and Shortcode Templating to learn how to build your own.

Code Blocks

Hugo supports GitHub-flavored markdown's use of triple back ticks, as well as provides a special highlight nested shortcode to render syntax highlighting via Pygments. For usage examples and a complete explanation, see the syntax highlighting documentation in developer tools.


Mmark is a fork of BlackFriday and markdown superset that is well suited for writing IETF documentation. You can see examples of the syntax in the Mmark GitHub repository or the full syntax on Miek Gieben's website.

Use Mmark

As Hugo ships with Mmark, using the syntax is as easy as changing the extension of your content files from .md to .mmark.

In the event that you want to only use Mmark in specific files, you can also define the Mmark syntax in your content's front matter:

title: My Post
date: 2017-04-01
markup: mmark

{{% warning %}} Thare are some features not available in Mmark; one example being that shortcodes are not translated when used in an included .mmark file (#3131), and EXTENSION_ABBREVIATION (#1970) and the aforementioned GFM todo lists (#2270) are not fully supported. Contributions are welcome. {{% /warning %}}

MathJax with Hugo

MathJax is a JavaScript library that allows the display of mathematical expressions described via a LaTeX-style syntax in the HTML (or Markdown) source of a web page. As it is a pure a JavaScript library, getting it to work within Hugo is fairly straightforward, but does have some oddities that will be discussed here.

This is not an introduction into actually using MathJax to render typeset mathematics on your website. Instead, this page is a collection of tips and hints for one way to get MathJax working on a website built with Hugo.

Enable MathJax

The first step is to enable MathJax on pages that you would like to have typeset math. There are multiple ways to do this (adventurous readers can consult the Loading and Configuring section of the MathJax documentation for additional methods of including MathJax), but the easiest way is to use the secure MathJax CDN by include a <script> tag for the officially recommended secure CDN (

{{< code file="add-mathjax-to-page.html" >}}

<script type="text/javascript" src=""> </script>

{{< /code >}}

One way to ensure that this code is included in all pages is to put it in one of the templates that live in the layouts/partials/ directory. For example, I have included this in the bottom of my template footer.html because I know that the footer will be included in every page of my website.

Options and Features

MathJax is a stable open-source library with many features. I encourage the interested reader to view the MathJax Documentation, specifically the sections on Basic Usage and MathJax Configuration Options.

Issues with Markdown

{{% note %}} The following issues with Markdown assume you are using .md for content and BlackFriday for parsing. Using Mmark as your content format will obviate the need for the following workarounds.

When using Mmark with MathJax, use displayMath: [['$$','$$'], ['\\[','\\]']]. See the Mmark for more information. In addition to MathJax, Mmark has been shown to work well with KaTeX. See this related blog post from a Hugo user. {{% /note %}}

After enabling MathJax, any math entered between proper markers (see the MathJax documentation) will be processed and typeset in the web page. One issue that comes up, however, with Markdown is that the underscore character (_) is interpreted by Markdown as a way to wrap text in emph blocks while LaTeX (MathJax) interprets the underscore as a way to create a subscript. This "double speak" of the underscore can result in some unexpected and unwanted behavior.


There are multiple ways to remedy this problem. One solution is to simply escape each underscore in your math code by entering \_ instead of _. This can become quite tedious if the equations you are entering are full of subscripts.

Another option is to tell Markdown to treat the MathJax code as verbatim code and not process it. One way to do this is to wrap the math expression inside a <div> </div> block. Markdown would ignore these sections and they would get passed directly on to MathJax and processed correctly. This works great for display style mathematics, but for inline math expressions the line break induced by the <div> is not acceptable. The syntax for instructing Markdown to treat inline text as verbatim is by wrapping it in backticks (`). You might have noticed, however, that the text included in between backticks is rendered differently than standard text (on this site these are items highlighted in red). To get around this problem, we could create a new CSS entry that would apply standard styling to all inline verbatim text that includes MathJax code. Below I will show the HTML and CSS source that would accomplish this (note this solution was adapted from this blog post---all credit goes to the original author).

{{< code file="mathjax-markdown-solution.html" >}}

<script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ['\\(','\\)']], displayMath: [['$$','$$'], ['\[','\]']], processEscapes: true, processEnvironments: true, skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'], TeX: { equationNumbers: { autoNumber: "AMS" }, extensions: ["AMSmath.js", "AMSsymbols.js"] } } }); </script> <script type="text/x-mathjax-config"> MathJax.Hub.Queue(function() { // Fix tags after MathJax finishes running. This is a // hack to overcome a shortcoming of Markdown. Discussion at // var all = MathJax.Hub.getAllJax(), i; for(i = 0; i < all.length; i += 1) { all[i].SourceElement().parentNode.className += ' has-jax'; } }); </script>

{{< /code >}}

As before, this content should be included in the HTML source of each page that will be using MathJax. The next code snippet contains the CSS that is used to have verbatim MathJax blocks render with the same font style as the body of the page.

{{< code file="mathjax-style.css" >}} code.has-jax { font: inherit; font-size: 100%; background: inherit; border: inherit; color: #515151; } {{< /code >}}

In the CSS snippet, notice the line color: #515151;. #515151 is the value assigned to the color attribute of the body class in my CSS. In order for the equations to fit in with the body of a web page, this value should be the same as the color of the body.


With this setup, everything is in place for a natural usage of MathJax on pages generated using Hugo. In order to include inline mathematics, just put LaTeX code in between `$ TeX Code $` or `\( TeX Code \)`. To include display style mathematics, just put LaTeX code in between <div>$$TeX Code$$</div>. All the math will be properly typeset and displayed within your Hugo generated web page!

Additional Formats Through External Helpers

Hugo has new concept called external helpers. It means that you can write your content using Asciidoc, reStructuredText. If you have files with associated extensions, Hugo will call external commands to generate the content. (See the Hugo source code for external helpers.)

For example, for Asciidoc files, Hugo will try to call the asciidoctor or asciidoc command. This means that you will have to install the associated tool on your machine to be able to use these formats. (See the Asciidoctor docs for installation instructions).

To use these formats, just use the standard extension and the front matter exactly as you would do with natively supported .md files.

{{% warning "Performance of External Helpers" %}} Because additional formats are external commands generation performance will rely heavily on the performance of the external tool you are using. As this feature is still in its infancy, feedback is welcome. {{% /warning %}}

Learn Markdown

Markdown syntax is simple enough to learn in a single sitting. The following are excellent resources to get you up and running:

Front Matter

Front matter allows you to keep metadata attached to an instance of a content type---i.e., embedded inside a content file---and is one of the many features that gives Hugo its strength.

Front Matter Formats

Hugo supports three formats for front matter, each with their own identifying tokens.

TOML : identified by opening and closing +++.

YAML : identified by opening and closing ---.

JSON : a single JSON object surrounded by '{' and '}', followed by a new line.

TOML Example

title = "spf13-vim 3.0 release and new website"
description = "spf13-vim is a cross platform distribution of vim plugins and resources for Vim."
tags = [ ".vimrc", "plugins", "spf13-vim", "vim" ]
date = "2012-04-06"
categories = [
slug = "spf13-vim-3-0-release-and-new-website"

YAML Example

title: "spf13-vim 3.0 release and new website"
description: "spf13-vim is a cross platform distribution of vim plugins and resources for Vim."
#tags: [ ".vimrc", "plugins", "spf13-vim", "vim" ]
lastmod: 2015-12-23
date: "2012-04-06"
  - "Development"
  - "VIM"
slug: "spf13-vim-3-0-release-and-new-website"

JSON Example

    "title": "spf13-vim 3.0 release and new website",
    "description": "spf13-vim is a cross platform distribution of vim plugins and resources for Vim.",
    "tags": [ ".vimrc", "plugins", "spf13-vim", "vim" ],
    "date": "2012-04-06",
    "categories": [
    "slug": "spf13-vim-3-0-release-and-new-website"

Front Matter Variables


There are a few predefined variables that Hugo is aware of. See Page Variables for how to call many of these predefined variables in your templates.

aliases : an array of one or more aliases (e.g., old published paths of renamed content) that will be created in the output directory structure . See Aliases for details.

date : the datetime at which the content was created; note this value is auto-populated according to Hugo's built-in archetype.

description : the description for the content.

draft : if true, the content will not be rendered unless the --buildDrafts flag is passed to the hugo command.

expiryDate : the datetime at which the content should no longer be published by Hugo; expired content will not be rendered unless the --buildExpired flag is passed to the hugo command.

isCJKLanguage : if true, Hugo will explicitly treat the content as a CJK language; both .Summary and .WordCount work properly in CJK languages.

keywords : the meta keywords for the content.

layout : the layout Hugo should select from the lookup order when rendering the content. If a type is not specified in the front matter, Hugo will look for the layout of the same name in the layout directory that corresponds with a content's section. See "Defining a Content Type"

lastmod : the datetime at which the content was last modified.

linkTitle : used for creating links to content; if set, Hugo defaults to using the linktitle before the title. Hugo can also order lists of content by linktitle.

markup : experimental; specify "rst" for reStructuredText (requiresrst2html) or "md" (default) for Markdown.

outputs : allows you to specify output formats specific to the content. See output formats.

publishDate : if in the future, content will not be rendered unless the --buildFuture flag is passed to hugo.

slug : appears as the tail of the output URL. A value specified in front matter will override the segment of the URL based on the filename.

taxonomies : these will use the field name of the plural form of the index; see the tags and categories in the above front matter examples.

title : the title for the content.

type : the type of the content; this value will be automatically derived from the directory (i.e., the section) if not specified in front matter.

url : the full path to the content from the web root. It makes no assumptions about the path of the content file. It also ignores any language prefixes of the multilingual feature.

weight : used for ordering your content in lists.

{{% note "Hugo's Default URL Destinations" %}} If neither slug nor url is present and permalinks are not configured otherwise in your site config file, Hugo will use the filename of your content to create the output URL. See Content Organization for an explanation of paths in Hugo and URL Management for ways to customize Hugo's default behaviors. {{% /note %}}


You can add fields to your front matter arbitrarily to meet your needs. These user-defined key-values are placed into a single .Params variable for use in your templates.

The following fields can be accessed via .Params.include_toc and .Params.show_comments, respectively. The Variables section provides more information on using Hugo's page- and site-level variables in your templates.

include_toc: true
show_comments: false

These two user-defined fields can then be accessed via .Params.include_toc and .Params.show_comments, respectively. The Variables section provides more information on using Hugo's page- and site-level variables in your templates.

Order Content Through Front Matter

You can assign content-specific weight in the front matter of your content. These values are especially useful for ordering in list views. You can use weight for ordering of content and the convention of <TAXONOMY>_weight for ordering content within a taxonomy. See Ordering and Grouping Hugo Lists to see how weight can be used to organize your content in list views.

Override Global Markdown Configuration

It's possible to set some options for Markdown rendering in a content's front matter as an override to the BlackFriday rendering options set in your project configuration.

Front Matter Format Specs


What a Shortcode is

Hugo loves Markdown because of its simple content format, but there are times when Markdown falls short. Often, content authors are forced to add raw HTML (e.g., video <iframes>) to Markdown content. We think this contradicts the beautiful simplicity of Markdown's syntax.

Hugo created shortcodes to circumvent these limitations.

A shortcode is a simple snippet inside a content file that Hugo will render using a predefined template. Note that shortcodes will not work in template files. If you need the type of drop-in functionality that shortcodes provide but in a template, you most likely want a partial template instead.

In addition to cleaner Markdown, shortcodes can be updated any time to reflect new classes, techniques, or standards. At the point of site generation, Hugo shortcodes will easily merge in your changes. You avoid a possibly complicated search and replace operation.

Use Shortcodes

In your content files, a shortcode can be called by calling {{%/* shortcodename parameters */%}}. Shortcode parameters are space delimited, and parameters with internal spaces can be quoted.

The first word in the shortcode declaration is always the name of the shortcode. Parameters follow the name. Depending upon how the shortcode is defined, the parameters may be named, positional, or both, although you can't mix parameter types in a single call. The format for named parameters models that of HTML with the format name="value".

Some shortcodes use or require closing shortcodes. Again like HTML, the opening and closing shortcodes match (name only) with the closing declaration, which is prepended with a slash.

Here are two examples of paired shortcodes:

{{%/* mdshortcode */%}}Stuff to `process` in the *center*.{{%/* /mdshortcode */%}}
{{</* highlight go */>}} A bunch of code here {{</* /highlight */>}}

The examples above use two different delimiters, the difference being the % character in the first and the <> characters in the second.

Shortcodes with Markdown

The % character indicates that the shortcode's inner content---called in the shortcode template with the .Inner variable---needs further processing by the page's rendering processor (i.e. markdown via Blackfriday). In the following example, Blackfriday would convert **World** to <strong>World</strong>:

{{%/* myshortcode */%}}Hello **World!**{{%/* /myshortcode */%}}

Shortcodes Without Markdown

The < character indicates that the shortcode's inner content does not need further rendering. Often shortcodes without markdown include internal HTML:

{{</* myshortcode */>}}<p>Hello <strong>World!</strong></p>{{</* /myshortcode */>}}

Nested Shortcodes

You can call shortcodes within other shortcodes by creating your own templates that leverage the .Parent variable. .Parent allows you to check the context in which the shortcode is being called. See Shortcode templates.

Use Hugo's Built-in Shortcodes

Hugo ships with a set of predefined shortcodes that represent very common usage. These shortcodes are provided for author convenience and to keep your markdown content clean.


figure is an extension of the image syntax in markdown, which does not provide a shorthand for the more semantic HTML5 <figure> element.

The figure shortcode can use the following named parameters:

  • src
  • link
  • title
  • caption
  • class
  • attr (i.e., attribution)
  • attrlink
  • alt

Example figure Input

{{< code file="" >}} {{</* figure src="/media/spf13.jpg" title="Steve Francia" */>}} {{< /code >}}

Example figure Output

{{< output file="figure-output-example.html" >}}

Steve Francia

{{< /output >}}


Bloggers often want to include GitHub gists when writing posts. Let's suppose we want to use the gist at the following url:

We can embed the gist in our content via username and gist ID pulled from the URL:

{{</* gist spf13 7896402 */>}}

Example gist Input

If the gist contains several files and you want to quote just one of them, you can pass the filename (quoted) as an optional third argument:

{{< code file="" >}} {{</* gist spf13 7896402 "img.html" */>}} {{< /code >}}

Example gist Output

{{< output file="gist-output.html" >}} {{< gist spf13 7896402 >}} {{< /output >}}

Example gist Display

To demonstrate the remarkably efficiency of Hugo's shortcode feature, we have embedded the spf13 gist example in this page. The following simulates the experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.

{{< gist spf13 7896402 >}}


This shortcode will convert the source code provided into syntax-highlighted HTML. Read more on highlighting. highlight takes exactly one required language parameter and requires a closing shortcode.

Example highlight Input

{{< code file="content/tutorials/" >}} {{</* highlight html */>}}

{{ .Title }}

{{ range .Data.Pages }} {{ .Render "summary"}} {{ end }}
{{}} {{< /code >}}

Example highlight Output

The highlight shortcode example above would produce the following HTML when the site is rendered:

{{< output file="tutorials/learn-html/index.html" >}} <section id="main"> <div> <h1 id="title">{{ .Title }}</h1> {{ range .Data.Pages }} {{ .Render "summary"}} {{ end }} </div> </section> {{< /output >}}

{{% note "More on Syntax Highlighting" %}} To see even more options for adding syntax-highlighted code blocks to your website, see Syntax Highlighting in Developer Tools. {{% /note %}}


If you'd like to embed a photo from Instagram, you only need the photo's ID. You can discern an Instagram photo ID from the URL:

Example instagram Input

{{< code file="" >}} {{</* instagram BWNjjyYFxVx */>}} {{< /code >}}

You also have the option to hide the caption:

{{< code file="" >}} {{</* instagram BWNjjyYFxVx hidecaption */>}} {{< /code >}}

Example instagram Output

By adding the preceding hidecaption example, the following HTML will be added to your rendered website's markup:

{{< output file="instagram-hide-caption-output.html" >}} {{< instagram BWNjjyYFxVx hidecaption >}} {{< /output >}}

Example instagram Display

Using the preceding instagram with hidecaption` example above, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.

{{< instagram BWNjjyYFxVx hidecaption >}}

ref and relref

These shortcodes will look up the pages by their relative path (e.g., blog/ or their logical name ( and return the permalink (ref) or relative permalink (relref) for the found page.

ref and relref also make it possible to make fragmentary links that work for the header links generated by Hugo.

{{% note "More on Cross References" %}} Read a more extensive description of ref and relref in the cross references documentation. {{% /note %}}

ref and relref take exactly one required parameter of reference, quoted and in position 0.

Example ref and relref Input

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

Example ref and relref Output

Assuming that standard Hugo pretty URLs are turned on.

<a href="/blog/neat">Neat</a>
<a href="/about/#who:c28654c202e73453784cfd2c5ab356c0">Who</a>


To embed slides from Speaker Deck, click on "< /> Embed" (under Share right next to the template on Speaker Deck) and copy the URL:

<script async class="speakerdeck-embed" data-id="4e8126e72d853c0060001f97" data-ratio="1.33333333333333" src="//"></script>

speakerdeck Example Input

Extract the value from the field data-id and pass it to the shortcode:

{{< code file="" >}} {{</* speakerdeck 4e8126e72d853c0060001f97 */>}} {{< /code >}}

speakerdeck Example Output

{{< output file="" >}} {{< speakerdeck 4e8126e72d853c0060001f97 >}} {{< /output >}}

speakerdeck Example Display

For the preceding speakerdeck example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.

{{< speakerdeck 4e8126e72d853c0060001f97 >}}


You want to include a single tweet into your blog post? Everything you need is the URL of the tweet:

Example tweet Input

Pass the tweet's ID from the URL as a parameter to the tweet shortcode:

{{< code file="" >}} {{</* tweet 877500564405444608 */>}} {{< /code >}}

Example tweet Output

Using the preceding tweet example, the following HTML will be added to your rendered website's markup:

{{< output file="example-tweet-output.html" >}} {{< tweet 877500564405444608 >}} {{< /output >}}

Example tweet Display

Using the preceding tweet example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.

{{< tweet 877500564405444608 >}}


Adding a video from Vimeo is equivalent to the YouTube shortcode above.

Example vimeo Input

Extract the ID from the video's URL and pass it to the vimeo shortcode:

{{< code file="" >}} {{</* vimeo 146022717 */>}} {{< /code >}}

Example vimeo Output

Using the preceding vimeo example, the following HTML will be added to your rendered website's markup:

{{< output file="example-vimeo-output.html" >}} {{< vimeo 146022717 >}} {{< /output >}}

{{% tip %}} If you want to further customize the visual styling of the YouTube or Vimeo output, add a class named parameter when calling the shortcode. The new class will be added to the <div> that wraps the <iframe> and will remove the inline styles. Note that you will need to call the id as a named parameter as well.

{{</* vimeo id="146022717" class="my-vimeo-wrapper-class" */>}}

{{% /tip %}}

Example vimeo Display

Using the preceding vimeo example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.

{{< vimeo 146022717 >}}


The youtube shortcode embeds a responsive video player for YouTube videos. Only the ID of the video is required, e.g.:

Example youtube Input

Copy the YouTube video ID that follows v= in the video's URL and pass it to the youtube shortcode:

{{< code file="" >}} {{</* youtube w7Ft2ymGmfc */>}} {{< /code >}}

Furthermore, you can automatically start playback of the embedded video by setting the autoplay parameter to true. Remember that you can't mix named an unnamed parameters, so you'll need to assign the yet unnamed video id to the parameter id:

{{< code file="" >}} {{</* youtube id="w7Ft2ymGmfc" autoplay="true" */>}} {{< /code >}}

Example youtube Output

Using the preceding youtube example, the following HTML will be added to your rendered website's markup:

{{< code file="example-youtube-output.html" >}} {{< youtube id="w7Ft2ymGmfc" autoplay="true" >}} {{< /code >}}

Example youtube Display

Using the preceding youtube example (without autoplay="true"), the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup. The video is also include in the Quick Start of the Hugo documentation.

{{< youtube w7Ft2ymGmfc >}}

Create Custom Shortcodes

To learn more about creating custom shortcodes, see the shortcode template documentation.

Content Sections

{{% note %}} This section is not updated with the new nested sections support in Hugo 0.24, see {{% /note %}} {{% todo %}} See above {{% /todo %}}

Hugo believes that you organize your content with a purpose. The same structure that works to organize your source content is used to organize the rendered site (see directory structure).

Following this pattern, Hugo uses the top level of your content organization as the content section.

The following example shows a content directory structure for a website that has three sections: "authors," "events," and "posts":

└── content
    ├── authors
    |   ├──     // <-
    |   ├──   // <-
    |   └──   // <-
    └── events
    |   ├──     // <-
    |   ├──    // <-
    |   ├──    // <-
    |   └──    // <-
    └── posts
    |   ├──     // <-
    |   ├──    // <-
    |   ├──    // <-
    |   ├──    // <-
    |   ├──    // <-
    |   └──    // <-

Content Section Lists

Hugo will automatically create pages for each section root that list all of the content in that section. See the documentation on section templates for details on customizing the way these pages are rendered.

As of Hugo v0.18, section pages can also have a content file and front matter. These section content files must be placed in their corresponding section folder and named in order for Hugo to correctly render the front matter and content.

{{% warning " vs" %}} Hugo themes developed before v0.18 often used an, without the leading underscore [_]) in a content section as a hack to emulate the behavior of The hack may work...sometimes; however, the order of page rendering can be unpredictable in Hugo. What works now may fail to render appropriately as your site grows. It is strongly advised to use as content for your section index pages. Note:'s layout, as representative of a section, is a list page template and not a single page template. If you want to alter the new default behavior for, configure disableKinds accordingly in your site's configuration. {{% /warning %}}

Content Section vs Content Type

By default, everything created within a section will use the content type that matches the section name. For example, Hugo will assume that posts/ has a posts content type. If you are using an archetype for your posts section, Hugo will generate front matter according to what it finds in archetypes/


Larger sites often have multiple content authors. Hugo provides standardized author profiles to organize relationships between content and content creators for sites operating under a distributed authorship model.

Author Profiles

You can create a profile containing metadata for each author on your website. These profiles have to be saved under data/_authors/. The filename of the profile will later be used as an identifier. This way Hugo can associate content with one or multiple authors. An author's profile can be defined in the JSON, YAML, or TOML format.

Example: Author Profile

Let's suppose Alice Allison is a blogger. A simple unique identifier would be alice. Now, we have to create a file called alice.toml in the data/_authors/ directory. The following example is the standardized template written in TOML:

{{< code file="data/_authors/alice.toml" >}} givenName = "Alice" # or firstName as alias familyName = "Allison" # or lastName as alias displayName = "Alice Allison" thumbnail = "static/authors/alice-thumb.jpg" image = "static/authors/alice-full.jpg" shortBio = "My name is Alice and I'm a blogger." bio = "My name is Alice and I'm a blogger... some other stuff" email = "" weight = 10

[social] facebook = "alice.allison" twitter = "alice" googleplus = "aliceallison1" website = ""

[params] random = "whatever you want" {{< /code >}}

All variables are optional but it's advised to fill all important ones (e.g. names and biography) because themes can vary in their usage.

You can store files for the thumbnail and image attributes in the static folder. Then add the path to the photos relative to static; e.g., /static/path/to/thumbnail.jpg.

weight allows you to define the order of an author in an .Authors list and can be accessed on list or via the .Site.Authors variable.

The social section contains all the links to the social network accounts of an author. Hugo is able to generate the account links for the most popular social networks automatically. This way, you only have to enter your username. You can find a list of all supported social networks here. All other variables, like website in the example above remain untouched.

The params section can contain arbitrary data much like the same-named section in the config file. What it contains is up to you.

Associate Content Through Identifiers

Earlier it was mentioned that content can be associated with an author through their corresponding identifier. In our case, blogger Alice has the identifier alice. In the front matter of a content file, you can create a list of identifiers and assign it to the authors variable. Here are examples for alice using YAML and TOML, respectively.

title: Why Hugo is so Awesome
date: 2016-08-22T14:27:502:00
authors: ["alice"]

Nothing to read here. Move along...
title = Why Hugo is so Awesome
date = "2016-08-22T14:27:502:00"
authors: ["alice"]

Nothing to read here. Move along...

Future authors who might work on this blog post can append their identifiers to the authors array in the front matter as well.

Work with Templates

After a successful setup it's time to give some credit to the authors by showing them on the website. Within the templates Hugo provides a list of the author's profiles if they are listed in the authors variable within the front matter.

The list is accessible via the .Authors template variable. Printing all authors of a the blog post is straight forward:

{{ range .Authors }}
    {{ .DisplayName }}
{{ end }}
=> Alice Allison

Even if there are co-authors you may only want to show the main author. For this case you can use the .Author template variable (note the singular form). The template variable contains the profile of the author that is first listed with his identifier in the front matter.

{{% note %}} You can find a list of all template variables to access the profile information in Author Variables. {{% /note %}}

Link Social Network Accounts

As aforementioned, Hugo is able to generate links to profiles of the most popular social networks. The following social networks with their corrersponding identifiers are supported: github, facebook, twitter, googleplus, pinterest, instagram, youtube and linkedin.

This is can be done with the .Social.URL function. Its only parameter is the name of the social network as they are defined in the profile (e.g. facebook, googleplus). Custom variables like website remain as they are.

Most articles feature a small section with information about the author at the end. Let's create one containing the author's name, a thumbnail, a (summarized) biography and links to all social networks:

{{< code file="layouts/partials/author-info.html" download="author-info.html" >}} {{ with .Author }}

{{ .DisplayName }}

{{ .DisplayName }}

{{ .ShortBio }}

{{ end }} {{< /code >}}

Who Published What?

That question can be answered with a list of all authors and another list containing all articles that they each have written. Now we have to translate this idea into templates. The taxonomy feature allows us to logically group content based on information that they have in common; e.g. a tag or a category. Well, many articles share the same author, so this should sound familiar, right?

In order to let Hugo know that we want to group content based on their author, we have to create a new taxonomy called author (the name corresponds to the variable in the front matter). Here is the snippet in a config.yaml and config.toml, respectively:

    author: authors
    author = "authors"

List All Authors

In the next step we can create a template to list all authors of your website. Later, the list can be accessed at Create a new template in the layouts/taxonomy/ directory called authors.term.html. This template will be exclusively used for this taxonomy.

{{< code file="layouts/taxonomy/author.term.html" download="author.term.html" >}}

{{< /code >}}

.Data.Terms contains the identifiers of all authors and we can range over it to create a list with all author names. The $profile variable gives us access to the profile of the current author. This allows you to generate a nice info box with a thumbnail, a biography and social media links, like at the end of a blog post.

List Each Author's Publications

Last but not least, we have to create the second list that contains all publications of an author. Each list will be shown in its own page and can be accessed at<IDENTIFIER>. Replace <IDENTIFIER> with a valid author identifier like alice.

The layout for this page can be defined in the template layouts/taxonomy/author.html.

{{< code file="layouts/taxonomy/author.html" download="author.html" >}} {{ range .Data.Pages }}

{{ .Title }}

written by {{ .Author.DisplayName }} {{ .Summary }} {{ end }} {{< /code >}}

The example above generates a simple list of all posts written by a single author. Inside the loop you've access to the complete set of page variables. Therefore, you can add additional information about the current posts like the publishing date or the tags.

With a lot of content this list can quickly become very long. Consider to use the pagination feature. It splits the list into smaller chunks and spreads them over multiple pages.

Content Types

A content type can have a unique set of metadata (i.e., front matter) or customized template and can be created by the hugo new command via archetypes.

What is a Content Type

[Tumblr][] is a good example of a website with multiple content types. A piece of "content" could be a photo, quote, or a post, each with different sets of metadata and different visual rendering.

Assign a Content Type

Hugo assumes that your site will be organized into sections and each section represents a corresponding type. This is to reduce the amount of configuration necessary for new Hugo projects.

If you are taking advantage of this default behavior, each new piece of content you place into a section will automatically inherit the type. Therefore a new file created at content/posts/ will automatically be assigned the type posts. Alternatively, you can set the content type in a content file's front matter in the field "type".

Create New Content of a Specific Type

You can manually add files to your content directories, but Hugo can create and populate a new content file with preconfigured front matter via archetypes.

Define a Content Type

Creating a new content type is easy. You simply define the templates and archetype unique to your new content type, or Hugo will use defaults.

{{% note "Declaring Content Types" %}} Remember, all of the following are optional. If you do not specifically declare content types in your front matter or develop specific layouts for content types, Hugo is smart enough to assume the content type from the file path and section. (See Content Sections for more information.) {{% /note %}}

The following examples take you stepwise through creating a new type layout for a content file that contains the following front matter:

{{< code file="content/events/" copy="false" >}} +++ title = My First Event date = "2016-06-24T19:20:04-07:00" description = "Today is my 36th birthday. How time flies." type = "event" layout = "birthday" +++ {{< /code >}}

By default, Hugo assumes *.md under events is of the events content type. However, we have specified that this particular file at content/events/ is of type event and should render using the birthday layout.

Create a Type Layout Directory

Create a directory with the name of the type in /layouts. For creating these custom layouts, type is always singular; e.g., events => event and posts => post.

For this example, you need to create layouts/event/birthday.html.

{{% note %}} If you have multiple content files in your events directory that are of the special type and you don't want to define the layout specifically for each piece of content, you can create a layout at layouts/special/single.html to observe the single page template lookup order. {{% /note %}}

{{% warning %}} With the "everything is a page" data model introduced in v0.18 (see Content Organization), you can use in content directories to add both content and front matter to list pages. However, type and layout declared in the front matter of are not currently respected at build time as of v0.19. This is a known issue (#3005). {{% /warning %}}

Create Views

Many sites support rendering content in a few different ways; e.g., a single page view and a summary view to be used when displaying a list of section contents.

Hugo limits assumptions about how you want to display your content to an intuitive set of sane defaults and will support as many different views of a content type as your site requires. All that is required for these additional views is that a template exists in each /layouts/<TYPE> directory with the same name.

Custom Content Type Template Lookup Order

The lookup order for the content/events/ templates would be as follows:

  • layouts/event/birthday.html
  • layouts/event/single.html
  • layouts/events/single.html
  • layouts/_default/single.html

Create a Corresponding Archetype

We can then create a custom archetype with preconfigured front matter at in the /archetypes directory; i.e. archetypes/

Read Archetypes for more information on archetype usage with hugo new.



{{% note %}} This section is outdated, see {{% /note %}} {{% todo %}} See above {{% /todo %}}

What are Archetypes?

Archetypes are content files in the archetypes directory of your project that contain preconfigured front matter for your website's content types. Archetypes facilitate consistent metadata across your website content and allow content authors to quickly generate instances of a content type via the hugo new command.

{{< youtube S3Tj3UcTFz8 >}}

The hugo new generator for archetypes assumes your working directory is the content folder at the root of your project. Hugo is able to infer the appropriate archetype by assuming the content type from the content section passed to the CLI command:

hugo new <content-section>/<>

We can use this pattern to create a new .md file in the posts section:

{{< code file="" >}} hugo new posts/ {{< /code >}}

{{% note "Override Content Type in a New File" %}} To override the content type Hugo infers from [content-section], add the --kind flag to the end of the hugo new command. {{% /note %}}

Running this command in a new site that does not have default or custom archetypes will create the following file:

{{< output file="content/posts/" >}} +++ date = "2017-02-01T19:20:04-07:00" title = "my first post" draft = true +++ {{< /output >}}

{{% note %}} In this example, if you do not already have a content/posts directory, Hugo will create both content/posts/ and content/posts/ for you. {{% /note %}}

The auto-populated fields are worth examining:

  • title is generated from the new content's filename (i.e. in this case, my-first-post becomes "my first post")
  • date and title are the variables that ship with Hugo and are therefore included in all content files created with the Hugo CLI. date is generated in RFC 3339 format by way of Go's now() function, which returns the current time.
  • The third variable, draft = true, is not inherited by your default or custom archetypes but is included in Hugo's automatically scaffolded archetype for convenience.

Three variables per content file are often not enough for effective content management of larger websites. Luckily, Hugo provides a simple mechanism for extending the number of variables through custom archetypes, as well as default archetypes to keep content creation DRY.

Lookup Order for Archetypes

Similar to the lookup order for templates in your layouts directory, Hugo looks for a section- or type-specific archetype, then a default archetype, and finally an internal archetype that ships with Hugo. For example, Hugo will look for an archetype for content/posts/ in the following order:

  1. archetypes/
  2. archetypes/
  3. themes/<THEME>/archetypes/
  4. themes/<THEME>/archetypes/ (Auto-generated with hugo new site)

{{% note "Using a Theme Archetype" %}} If you wish to use archetypes that ship with a theme, the theme field must be specified in your configuration file. {{% /note %}}

Choose Your Archetype's Front Matter Format

By default, hugo new content files include front matter in the TOML format regardless of the format used in archetypes/*.md.

You can specify a different default format in your site configuration file file using the metaDataFormat directive. Possible values are toml, yaml, and json.

Default Archetypes

Default archetypes are convenient if your content's front matter stays consistent across multiple content sections.

Create the Default Archetype

When you create a new Hugo project using hugo new site, you'll notice that Hugo has already scaffolded a file at archetypes/

The following examples are from a site that's using tags and categories as taxonomies. If we assume that all content files will require these two key-values, we can create a archetype that extends Hugo's base archetype. In this example, we are including "golang" and "hugo" as tags and "web development" as a category.

{{< code file="archetypes/" >}} +++ tags = ["golang", "hugo"] categories = ["web development"] +++ {{< /code >}}

{{% warning "EOL Characters in Text Editors"%}} If you get an EOF error when using hugo new, add a carriage return after the closing +++ or --- for your TOML or YAML front matter, respectively. (See the troubleshooting article on EOF errors for more information.) {{% /warning %}}

Use the Default Archetype

With an archetypes/ in place, we can use the CLI to create a new post in the posts content section:

{{< code file="" >}} $ hugo new posts/ {{< /code >}}

Hugo then creates a new markdown file with the following front matter:

{{< output file="content/posts/" >}} +++ categories = ["web development"] date = "2017-02-01T19:20:04-07:00" tags = ["golang", "hugo"] title = "my new post" +++ {{< /output >}}

We see that the title and date key-values have been added in addition to the tags and categories key-values from archetypes/

{{% note "Ordering of Front Matter" %}} You may notice that content files created with hugo new do not respect the order of the key-values specified in your archetype files. This is a known issue. {{% /note %}}

Custom Archetypes

Suppose your site's posts section requires more sophisticated front matter than what has been specified in archetypes/ You can create a custom archetype for your posts at archetypes/ that includes the full set of front matter to be added to the two default archetypes fields.

Create a Custom Archetype

{{< code file="archetypes/">}} +++ description = "" tags = "" categories = "" +++ {{< /code >}}

Use a Custom Archetype

With an archetypes/ in place, you can use the Hugo CLI to create a new post with your preconfigured front matter in the posts content section:

{{< code file="" >}} $ hugo new posts/ {{< /code >}}

This time, Hugo recognizes our custom archetypes/ archetype and uses it instead of archetypes/ The generated file will now include the full list of front matter parameters, as well as the base archetype's title and date:

{{< output file="content/posts/" >}} +++ categories = "" date = 2017-02-13T17:24:43-08:00 description = "" tags = "" title = "post from custom archetype" +++ {{< /output >}}

Hugo Docs Custom Archetype

As an example of archetypes in practice, the following is the functions archetype from the Hugo docs:

{{< code file="archetypes/" >}} {{< readfile file="/themes/gohugoioTheme/archetypes/" >}} {{< /code >}}

{{% note %}} The preceding archetype is kept up to date with every Hugo build by using Hugo's readFile function. For similar examples, see Local File Templates. {{% /note %}}


What is a Taxonomy?

Hugo includes support for user-defined groupings of content called taxonomies. Taxonomies are classifications of logical relationships between content.


Taxonomy : a categorization that can be used to classify content

Term : a key within the taxonomy

Value : a piece of content assigned to a term

{{< youtube "-np9GX6cL38" >}}

Example Taxonomy: Movie Website

Let's assume you are making a website about movies. You may want to include the following taxonomies:

  • Actors
  • Directors
  • Studios
  • Genre
  • Year
  • Awards

Then, in each of the movies, you would specify terms for each of these taxonomies (i.e., in the front matter of each of your movie content files). From these terms, Hugo would automatically create pages for each Actor, Director, Studio, Genre, Year, and Award, with each listing all of the Movies that matched that specific Actor, Director, Studio, Genre, Year, and Award.

Movie Taxonomy Organization

To continue with the example of a movie site, the following demonstrates content relationships from the perspective of the taxonomy:

Actor                    <- Taxonomy
    Bruce Willis         <- Term
        The Sixth Sense    <- Content
        Unbreakable      <- Content
        Moonrise Kingdom <- Content
    Samuel L. Jackson    <- Term
        Unbreakable      <- Content
        The Avengers     <- Content
        xXx              <- Content

From the perspective of the content, the relationships would appear differently, although the data and labels used are the same:

Unbreakable                 <- Content
    Actors                  <- Taxonomy
        Bruce Willis        <- Term
        Samuel L. Jackson   <- Term
    Director                <- Taxonomy
        M. Night Shyamalan  <- Term
Moonrise Kingdom            <- Content
    Actors                  <- Taxonomy
        Bruce Willis        <- Term
        Bill Murray         <- Term
    Director                <- Taxonomy
        Wes Anderson        <- Term

Hugo Taxonomy Defaults

Hugo natively supports taxonomies.

Without adding a single line to your site's configuration file, Hugo will automatically create taxonomies for tags and categories. If you do not want Hugo to create any taxonomies, set disableKinds in your site's configuration to the following:

disableKinds = ["taxonomy","taxonomyTerm"]

Default Destinations

When taxonomies are used---and taxonomy templates are provided---Hugo will automatically create both a page listing all the taxonomy's terms and individual pages with lists of content associated with each term. For example, a categories taxonomy declared in your configuration and used in your content front matter will create the following pages:

Configure Taxonomies

Taxonomies must be defined in your website configuration before they can be used throughout the site. You need to provide both the plural and singular labels for each taxonomy. For example, singular key = "plural value" for TOML and singular key: "plural value" for YAML.

Example: TOML Taxonomy Configuration

  tag = "tags"
  category = "categories"
  series = "series"

Example: YAML Taxonomy Configuration

  tag: "tags"
  category: "categories"
  series: "series"

Preserve Taxonomy Values

By default, taxonomy names are normalized.

Therefore, if you want to have a taxonomy term with special characters such as Gérard Depardieu instead of Gerard Depardieu, set the value for preserveTaxonomyNames to true in your site configuration. Hugo will then preserve special characters in taxonomy values but will still title-ize the values for titles and normalize them in URLs.

Note that if you use preserveTaxonomyNames and intend to manually construct URLs to the archive pages, you will need to pass the taxonomy values through the urlize template function.

{{% note %}} You can add content and front matter to your taxonomy list and taxonomy terms pages. See Content Organization for more information on how to add an for this purpose.

Note also that taxonomy permalinks are not configurable. {{% /note %}}

Add Taxonomies to Content

Once a taxonomy is defined at the site level, any piece of content can be assigned to it, regardless of content type or content section.

Assigning content to a taxonomy is done in the front matter. Simply create a variable with the plural name of the taxonomy and assign all terms you want to apply to the instance of the content type.

{{% note %}} If you would like the ability to quickly generate content files with preconfigured taxonomies or terms, read the docs on Hugo archetypes. {{% /note %}}

Example: TOML Front Matter with Taxonomies

title = "Hugo: A fast and flexible static site generator"
tags = [ "Development", "Go", "fast", "Blogging" ]
categories = [ "Development" ]
series = [ "Go Web Dev" ]
slug = "hugo"
project_url = ""

Example: YAML Front Matter with Taxonomies

title: "Hugo: A fast and flexible static site generator"
#tags: ["Development", "Go", "fast", "Blogging"]
categories: ["Development"]
series: ["Go Web Dev"]
slug: "hugo"
project_url: ""

Example: JSON Front Matter with Taxonomies

    "title": "Hugo: A fast and flexible static site generator",
    "tags": [
    "categories" : [
    "series" : [
        "Go Web Dev"
    "slug": "hugo",
    "project_url": ""

Order Taxonomies

A content file can assign weight for each of its associate taxonomies. Taxonomic weight can be used for sorting or ordering content in taxonomy list templates and is declared in a content file's front matter. The convention for declaring taxonomic weight is taxonomyname_weight.

The following TOML and YAML examples show a piece of content that has a weight of 22, which can be used for ordering purposes when rendering the pages assigned to the "a", "b" and "c" values of the tags taxonomy. It has also been assigned the weight of 44 when rendering the "d" category page.

Example: TOML Taxonomic weight

title = "foo"
tags = [ "a", "b", "c" ]
tags_weight = 22
categories = ["d"]
categories_weight = 44

Example: YAML Taxonomic weight

title: foo
#tags: [ "a", "b", "c" ]
tags_weight: 22
categories: ["d"]
categories_weight: 44

By using taxonomic weight, the same piece of content can appear in different positions in different taxonomies.

{{% note "Limits to Ordering Taxonomies" %}} Currently taxonomies only support the default weight => date ordering of list content. For more information, see the documentation on taxonomy templates. {{% /note %}}

Content Summaries

With the use of the .Summary page variable, Hugo generates summaries of content to use as a short version in summary views.

Summary Splitting Options

  • Hugo-defined Summary Split
  • User-defined Summary Split

It is natural to accompany the summary with links to the original content, and a common design pattern is to see this link in the form of a "Read More ..." button. See the .RelPermalink, .Permalink, and .Truncated page variables.

Hugo-defined: Automatic Summary Splitting

By default, Hugo automatically takes the first 70 words of your content as its summary and stores it into the .Summary page variable for use in your templates. Taking the Hugo-defined approach to summaries may save time, but it has pros and cons:

  • Pros: Automatic, no additional work on your part.
  • Cons: All HTML tags are stripped from the summary, and the first 70 words, whether they belong to a heading or to different paragraphs, are all put into one paragraph.

{{% note %}} The Hugo-defined summaries are set to use word count calculated by splitting the text by one or more consecutive white space characters. If you are creating content in a CJK language and want to use Hugo's automatic summary splitting, set hasCJKLanguage to true in you site configuration. {{% /note %}}

User-defined: Manual Summary Splitting

Alternatively, you may add the <!--more--> summary divider where you want to split the article. For org content, use # more where you want to split the article. Content that comes before the summary divider will be used as that content's summary and stored in the .Summary page variable with all HTML formatting intact.

{{% note "Summary Divider"%}} The concept of a summary divider is not unique to Hugo. It is also called the "more tag" or "excerpt separator" in other literature. {{% /note %}}

  • Pros: Freedom, precision, and improved rendering. All HTML tags and formatting are preserved.
  • Cons: Extra work for content authors, since they need to remember to type <!--more--> (or # more for org content) in each content file. This can be automated by adding the summary divider below the front matter of an archetype.

{{% warning "Be Precise with the Summary Divider" %}} Be careful to enter <!--more--> exactly; i.e., all lowercase and with no whitespace. {{% /warning %}}

Example: First 10 Articles with Summaries

You can show content summaries with the following code. You could use the following snippet, for example, in a [section template][].

{{< code file="page-list-with-summaries.html" >}} {{ range first 10 .Data.Pages }}

{{ .Title }}

{{ .Summary }}
{{ if .Truncated }} {{ end }} {{ end }} {{< /code >}}

Note how the .Truncated boolean valuable may be used to hide the "Read More..." link when the content is not truncated; i.e., when the summary contains the entire article.

[section template]: /templates/section-templates/

Cross References

The ref and relref shortcodes link documents together, both of which are built-in Hugo shortcodes. These shortcodes are also used to provide links to headings inside of your content, whether across documents or within a document. The only difference between ref and relref is whether the resulting URL is absolute ( or relative (/about/), respectively.

Use ref and relref

{{</* ref "document" */>}}
{{</* ref "#anchor" */>}}
{{</* ref "document#anchor" */>}}
{{</* relref "document" */>}}
{{</* relref "#anchor" */>}}
{{</* relref "document#anchor" */>}}

The single parameter to ref is a string with a content documentname (e.g., with or without an appended in-document anchor (#who) without spaces.

Document Names

The documentname is the name of a document, including the format extension; this may be just the filename, or the relative path from the content/ directory. With a document content/blog/, either format will produce the same result:

{{</* relref "blog/" */>}} => `/blog/post/`
{{</* relref "" */>}} => `/blog/post/`

If you have the same filename used across multiple sections, you should only use the relative path format; otherwise, the behavior will be undefined. This is best illustrated with an example content directory:

└── content
    ├── events
    │   └──
    ├── galleries
    │   └──
    ├── meta
    │   └──
    └── posts

To be sure to get the correct reference in this case, use the full path:

{{< code file="content/meta/" copy="false" >}} {{</* relref "events/" */>}} => /events/my-birthday/ {{< /code >}}

{{< todo >}}Remove this warning when is released.{{< /todo >}}

A relative document name must not begin with a slash (/).

{{</* relref "/events/" */>}} => ""

With Multiple Output Formats

If the page exists in multiple output formats, ref or relref can be used with a output format name:

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


When an anchor is provided by itself, the current page’s unique identifier will be appended; when an anchor is provided appended to documentname, the found page's unique identifier will be appended:

{{</* relref "#anchors" */>}} => #anchors:9decaf7
{{</* relref "about-hugo/" */>}} => /blog/post/#who:badcafe

The above examples render as follows for this very page as well as a reference to the "Content" heading in the Hugo docs features pageyoursite

{{</* relref "#who" */>}} => #who:9decaf7
{{</* relref "blog/" */>}} => /blog/post/#who:badcafe

More information about document unique identifiers and headings can be found [below]({{< ref "#hugo-heading-anchors" >}}).


  • {{</* ref "blog/" */>}} =>
  • {{</* ref "" */>}} =>
  • {{</* relref "" */>}} => /blog/post/
  • {{</* relref "blog/" */>}} => /blog/post/#tldr:caffebad
  • {{</* ref "#tldr" */>}} => #tldr:badcaffe
  • {{</* relref "#tldr" */>}} => #tldr:badcaffe

Hugo Heading Anchors

When using Markdown document types, Hugo generates heading anchors automatically. The generated anchor for this section is hugo-heading-anchors. Because the heading anchors are generated automatically, Hugo takes some effort to ensure that heading anchors are unique both inside a document and across the entire site.

Ensuring heading uniqueness across the site is accomplished with a unique identifier for each document based on its path. Unless a document is renamed or moved between sections in the filesystem, the unique identifier for the document will not change: blog/ will always have a unique identifier of 81df004c333b392d34a49fd3a91ba720.

ref and relref were added so you can make these reference links without having to know the document’s unique identifier. (The links in document tables of contents are automatically up-to-date with this value.)

{{</* relref "content-management/" */>}}

[shortcode]: /content-management/shortcodes/

URL Management


The default Hugo target directory for your built website is public/. However, you can change this value by specifying a different publishDir in your site configuration. The directories created at build time for a section reflect the position of the content's directory within the content folder and namespace matching its layout within the contentdir hierarchy.

The permalinks option in your site configuration allows you to adjust the directory paths (i.e., the URLs) on a per-section basis. This will change where the files are written to and will change the page's internal "canonical" location, such that template references to .RelPermalink will honor the adjustments made as a result of the mappings in this option.

{{% note "Default Publish and Content Folders" %}} These examples use the default values for publishDir and contentDir; i.e., publish and content, respectively. You can override the default values in your site's config file. {{% /note %}}

For example, if one of your sections is called post and you want to adjust the canonical path to be hierarchical based on the year, month, and post title, you could set up the following configurations in YAML and TOML, respectively.

YAML Permalinks Configuration Example

{{< code file="config.yml" copy="false" >}} permalinks: post: /:year/:month/:title/ {{< /code >}}

TOML Permalinks Configuration Example

{{< code file="config.toml" copy="false" >}} [permalinks] post = "/:year/:month/:title/" {{< /code >}}

Only the content under post/ will have the new URL structure. For example, the file content/post/ with date: 2017-02-27T19:20:00-05:00 in its front matter will render to public/2017/02/sample-entry/index.html at build time and therefore be reachable at

Permalink Configuration Values

The following is a list of values that can be used in a permalink definition in your site config file. All references to time are dependent on the content's date.

:year : the 4-digit year

:month : the 2-digit month

:monthname : the name of the month

:day : the 2-digit day

:weekday : the 1-digit day of the week (Sunday = 0)

:weekdayname : the name of the day of the week

:yearday : the 1- to 3-digit day of the year

:section : the content's section

:title : the content's title

:slug : the content's slug (or title if no slug is provided in the front matter)

:filename : the content's filename (without extension)


For people migrating existing published content to Hugo, there's a good chance you need a mechanism to handle redirecting old URLs.

Luckily, redirects can be handled easily with aliases in Hugo.

Example: Aliases

Let's assume you create a new piece of content at content/posts/ The content is a revision of your previous post at content/posts/ You can create an aliases field in the front matter of your new where you can add previous paths. The following examples show how to create this filed in TOML and YAML front matter, respectively.

TOML Front Matter

{{< code file="content/posts/" copy="false" >}} +++ aliases = [ "/posts/my-original-url/", "/2010/01/01/even-earlier-url.html" ] +++ {{< /code >}}

YAML Front Matter

{{< code file="content/posts/" copy="false" >}}

aliases: - /posts/my-original-url/ - /2010/01/01/even-earlier-url.html

{{< /code >}}

Now when you visit any of the locations specified in aliases---i.e., assuming the same site domain---you'll be redirected to the page they are specified on. For example, a visitor to will be immediately redirected to

Example: Aliases in Multilingual

On multilingual sites, each translation of a post can have unique aliases. To use the same alias across multiple languages, prefix it with the language code.

In /posts/

    - /es/posts/my-original-post/

How Hugo Aliases Work

When aliases are specified, Hugo creates a directory to match the alias entry. Inside the directory, Hugo creates an .html file specifying the canonical URL for the page and the new redirect target.

For example, a content file at posts/ with the following in the front matter:

title: My New post
aliases: [/posts/my-old-url/]

Assuming a baseURL of, the contents of the auto-generated alias .html found at will contain the following:

<!DOCTYPE html>
    <link rel="canonical" href=""/>
    <meta name=\"robots\" content=\"noindex\">
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <meta http-equiv="refresh" content="0; url="/>

The http-equiv="refresh" line is what performs the redirect, in 0 seconds in this case. If an end user of your website goes to, they will now be automatically redirected to the newer, correct URL. The addition of <meta name=\"robots\" content=\"noindex\"> lets search engine bots know they they should not crawl and index your new alias page.


You may customize this alias page by creating an alias.html template in the layouts folder of your site (i.e., layouts/alias.html). In this case, the data passed to the template is

Permalink : the link to the page being aliased

Page : the Page data for the page being aliased

Important Behaviors of Aliases

  1. Hugo makes no assumptions about aliases. They also do not change based on your UglyURLs setting. You need to provide absolute paths to your web root and the complete filename or directory.
  2. Aliases are rendered before any content are rendered and therefore will be overwritten by any content with the same location.

Pretty URLs

Hugo's default behavior is to render your content with "pretty" URLs. No non-standard server-side configuration is required for these pretty URLs to work.

The following demonstrates the concept:


Ugly URLs

If you would like to have what are often referred to as "ugly URLs" (e.g.,, set uglyurls = true or uglyurls: true in your site's config.toml or config.yaml, respectively. You can also use the --uglyURLs=true flag from the command line with hugo or hugo server..

If you want a specific piece of content to have an exact URL, you can specify this in the front matter under the url key. The following are examples of the same content directory and what the eventual URL structure will be when Hugo runs with its default behavior.

See Content Organization for more details on paths.

└── content
    └── about
    |   └──  // <-
    ├── post
    |   ├──   // <-
    |   ├── happy
    |   |   └──  // <-
    |   └──  // <-
    └── quote
        ├──       // <-
        └──      // <-

Here's the same organization run with hugo --uglyURLs:

└── content
    └── about
    |   └──  // <-
    ├── post
    |   ├──   // <-
    |   ├── happy
    |   |   └──    // <-
    |   └──  // <-
    └── quote
        ├──       // <-
        └──      // <-


By default, all relative URLs encountered in the input are left unmodified, e.g. /css/foo.css would stay as /css/foo.css. The canonifyURLs field in your site config has a default value of false.

By setting canonifyURLs to true, all relative URLs would instead be canonicalized using baseURL. For example, assuming you have baseURL =, the relative URL /css/foo.css would be turned into the absolute URL

Benefits of canonicalization include fixing all URLs to be absolute, which may aid with some parsing tasks. Note, however, that all modern browsers handle this on the client without issue.

Benefits of non-canonicalization include being able to have scheme-relative resource inclusion; e.g., so that http vs https can be decided according to how the page was retrieved.

{{% note "canonifyURLs default change" %}} In the May 2014 release of Hugo v0.11, the default value of canonifyURLs was switched from true to false, which we think is the better default and should continue to be the case going forward. Please verify and adjust your website accordingly if you are upgrading from v0.10 or older versions. {{% /note %}}

To find out the current value of canonifyURLs for your website, you may use the handy hugo config command added in v0.13.

hugo config | grep -i canon

Or, if you are on Windows and do not have grep installed:

hugo config | FINDSTR /I canon

Override URLS with Front Matter

In addition to specifying permalink values in your site configuration for different content sections, Hugo provides even more granular control for individual pieces of content.

Both slug and url can be defined in individual front matter. For more information on content destinations at build time, see Content Organization.

Relative URLs

By default, all relative URLs are left unchanged by Hugo, which can be problematic when you want to make your site browsable from a local file system.

Setting relativeURLs to true in your site configuration will cause Hugo to rewrite all relative URLs to be relative to the current content.

For example, if your /post/first/ page contains a link to /about/, Hugo will rewrite the URL to ../../about/.


{{% note "Lazy Blogger"%}} If all you want is a simple menu for your sections, see the "Section Menu for Lazy Bloggers" in Menu Templates. {{% /note %}}

You can do this:

  • Place content in one or many menus
  • Handle nested menus with unlimited depth
  • Create menu entries without being attached to any content
  • Distinguish active element (and active branch)

What is a Menu in Hugo?

A menu is a named array of menu entries accessible by name via the .Site.Menus site variable. For example, you can access your site's main menu via .Site.Menus.main.

{{% note "Menus on Multilingual Sites" %}} If you make use of the multilingual feature, you can define language-independent menus. {{% /note %}}

A menu entry has the following properties (i.e., variables) available to it:

.URL : string

.Name : string

.Menu : string

.Identifier : string

.Pre : template.HTML

.Post : template.HTML

.Weight : int

.Parent : string

.Children : Menu

Note that menus also have the following functions available as well:

.HasChildren : boolean

Additionally, there are some relevant functions available to menus on a page:

.IsMenuCurrent : (menu string, menuEntry *MenuEntry ) boolean

.HasMenuCurrent : (menu string, menuEntry *MenuEntry) boolean

Add content to menus

Hugo allows you to add content to a menu via the content's front matter.


If all you need to do is add an entry to a menu, the simple form works well.

A Single Menu

menu: "main"

Multiple Menus

menu: ["main", "footer"]


    parent: 'extras'
    weight: 20

Add Non-content Entries to a Menu

You can also add entries to menus that aren’t attached to a piece of content. This takes place in your Hugo project's config file.

Here’s an example snippet pulled from a config.toml:

{{< code file="config.toml" >}} [[menu.main]] name = "about hugo" pre = "" weight = -110 identifier = "about" url = "/about/" [[menu.main]] name = "getting started" pre = "" weight = -100 url = "/getting-started/" {{< /code >}}

Here's the equivalent snippet in a config.yaml:

{{< code file="config.yml" >}}

menu: docs: - Name: "about hugo" Pre: "" Weight: -110 Identifier: "about" URL: "/about/" - Name: "getting started" Pre: "" Weight: -100 URL: "/getting-started/"

{{< /code >}}

{{% note %}} The URLs must be relative to the context root. If the baseURL is, then the URLs in the menu must not include the context root mysite. Using an absolute URL will overide the baseURL. If the value used for URL in the above example is, the output will be {{% /note %}}


All nesting of content is done via the parent field.

The parent of an entry should be the identifier of another entry. The identifier should be unique (within a menu).

The following order is used to determine an Identifier:

.Name > .LinkTitle > .Title

This means that .Title will be used unless .LinkTitle is present, etc. In practice, .Name and .Identifier are only used to structure relationships and therefore never displayed.

In this example, the top level of the menu is defined in your site config file). All content entries are attached to one of these entries via the .Parent field.

Render Menus

See Menu Templates for information on how to render your site menus within your templates.

Table of Contents

{{% note "TOC Heading Levels are Fixed" %}} Currently, the {{.TableOfContents}} page variable does not allow you to specify which heading levels you want the TOC to render. See the related GitHub discussion (#1778). As such, the resulting <nav id="TableOfContents"><ul></ul></nav> is going to start at <h1> when pulling from {{.Content}}. {{% /note %}}


Create your markdown the way you normally would with the appropriate headings. Here is some example content:

<!-- Your front matter up here -->

## Introduction

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.

## My Heading

He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment.

### My Subheading

A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine and housed in a nice, gilded frame. It showed a lady fitted out with a fur hat and fur boa who sat upright, raising a heavy fur muff that covered the whole of her lower arm towards the viewer. Gregor then turned to look out the window at the dull weather. Drops

Hugo will take this Markdown and create a table of contents from ## Introduction, ## My Heading, and ### My Subheading and then store it in the page variable.TableOfContents.

The built-in .TableOfContents variables outputs a <nav id="TableOfContents"> element with a child <ul>, whose child <li> elements begin with any <h1>'s (i.e., # in markdown) inside your content.'

Template Example: Basic TOC

The following is an example of a very basic single page template:

{{< code file="layout/_default/single.html" download="single.html" >}} {{ define "main" }}

{{ .Title }}

{{ .Content }} {{ .TableOfContents }} {{ end }} {{< /code >}}

Template Example: TOC Partial

The following is a partial template that adds slightly more logic for page-level control over your table of contents. It assumes you are using a toc field in your content's front matter that, unless specifically set to false, will add a TOC to any page with a .WordCount (see Page Variables) greater than 400. This example also demonstrates how to use conditionals in your templating:

{{< code file="layouts/partials/toc.html" download="toc.html" >}} {{ if and (gt .WordCount 400 ) (ne .Params.toc "false") }}


{{.TableOfContents}} {{ end }} {{< /code >}}

{{% note %}} With the preceding example, even pages with > 400 words and toc not set to false will not render a table of contents if there are no headings in the page for the {{.TableOfContents}} variable to pull from. {{% /note %}}

single page template: /templates/single-page-templates/


Hugo ships with support for Disqus, a third-party service that provides comment and community capabilities to websites via JavaScript.

Your theme may already support Disqus, but if not, it is easy to add to your templates via Hugo's built-in Disqus partial.

Add Disqus

Hugo comes with all the code you need to load Disqus into your templates. Before adding Disqus to your site, you'll need to set up an account.

Configure Disqus

Disqus comments require you set a single value in your site's configuration file. The following show the configuration variable in a config.toml and config.yml, respectively:

disqusShortname = "yourdiscussshortname"
disqusShortname: "yourdiscussshortname"

For many websites, this is enough configuration. However, you also have the option to set the following in the front matter of a single content file:

  • disqus_identifier
  • disqus_title
  • disqus_url

Render Hugo's Built-in Disqus Partial Template

See Partial Templates to learn how to add the Disqus partial to your Hugo website's templates.

Comments Alternatives

There are a few alternatives to commenting on static sites for those who do not want to use Disqus:

Multilingual Mode

You should define the available languages in a Languages section in your site configuration.

Configure Languages

The following is an example of a TOML site configuration for a multilingual Hugo project:

{{< code file="config.toml" download="config.toml" >}} DefaultContentLanguage = "en" copyright = "Everything is mine"

[params.navigation] help = "Help"

[Languages] [Languages.en] title = "My blog" weight = 1 [Languages.en.params] linkedin = "english-link"

[] copyright = "Tout est à moi" title = "Mon blog" weight = 2 [] linkedin = "lien-francais" [] help = "Aide" {{< /code >}}

Anything not defined in a [Languages] block will fall back to the global value for that key (e.g., copyright for the English [en] language).

With the configuration above, all content, sitemap, RSS feeds, paginations, and taxonomy pages will be rendered below / in English (your default content language) and then below /fr in French.

When working with front matter Params in single page templates, omit the params in the key for the translation.

If you want all of the languages to be put below their respective language code, enable defaultContentLanguageInSubdir: true.

Only the obvious non-global options can be overridden per language. Examples of global options are baseURL, buildDrafts, etc.

Taxonomies and Blackfriday

Taxonomies and Blackfriday configuration can also be set per language:

{{< code file="bf-config.toml" >}} Taxonomies tag = "tags"

blackfriday angledQuotes = true hrefTargetBlank = true

[Languages] [Languages.en] weight = 1 title = "English" [] angledQuotes = false

[] weight = 2 title = "Français" [] plaque = "plaques" {{< /code >}}

Translate Your Content

Translated articles are identified by the name of the content file.

Examples of Translated Articles

  1. /content/
  2. /content/

In this example, the will be assigned the configured defaultContentLanguage.

  1. /content/
  2. /content/

This way, you can slowly start to translate your current content without having to rename everything. If left unspecified, the default value for defaultContentLanguage is en.

By having the same base filename, the content pieces are linked together as translated pieces.

If you need distinct URLs per language, you can set the slug in the non-default language file. For example, you can define a custom slug for a French translation in the front matter of content/ as follows:

slug: "a-propos"

At render, Hugo will build both /about/ and /a-propos/ as properly linked translated pages.

{{%note %}} Hugo currently uses the base filename as the translation key, which can be an issue with identical filenames in different sections. We will fix this in {{% /note %}} {{< todo >}}Rewrite/remove the above one issue is fixed.{{< /todo >}}

Link to Translated Content

To create a list of links to translated content, use a template similar to the following:

{{< code file="layouts/partials/i18nlist.html" >}} {{ if .IsTranslated }}

{{ i18n "translations" }}

{{ end }} {{< /code >}}

The above can be put in a partial (i.e., inside layouts/partials/) and included in any template, be it for a single content page or the homepage. It will not print anything if there are no translations for a given page, or if there are translations---in the case of the homepage, section listing, etc.---a site with only render one language.

The above also uses the i18n function described in the next section.

Translation of Strings

Hugo uses go-i18n to support string translations. See the project's source repository to find tools that will help you manage your translation workflows.

Translations are collected from the themes/<THEME>/i18n/ folder (built into the theme), as well as translations present in i18n/ at the root of your project. In the i18n, the translations will be merged and take precedence over what is in the theme folder. Language files should be named according to RFC 5646 with names such as en-US.toml, fr.toml, etc.

From within your templates, use the i18n function like this:

{{ i18n "home" }}

This uses a definition like this one in i18n/en-US.toml:

other = "Home"

Often you will want to use to the page variables in the translations strings. To do that, pass on the "." context when calling i18n:

{{ i18n "wordCount" . }}

This uses a definition like this one in i18n/en-US.toml:

other = "This article has {{ .WordCount }} words."

An example of singular and plural form:

one = "One minute read"
other = "{{.Count}} minutes read"

And then in the template:

{{ i18n "readingTime" .ReadingTime }}

To track down missing translation strings, run Hugo with the --i18n-warnings flag:

 hugo --i18n-warnings | grep i18n

Customize Dates

At the time of this writing, Golang does not yet have support for internationalized locales, but if you do some work, you can simulate it. For example, if you want to use French month names, you can add a data file like data/mois.yaml with this content:

1: "janvier"
2: "février"
3: "mars"
4: "avril"
5: "mai"
6: "juin"
7: "juillet"
8: "août"
9: "septembre"
10: "octobre"
11: "novembre"
12: "décembre"

... then index the non-English date names in your templates like so:

<time class="post-date" datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" | safeHTML }}">
  Article publié le {{ .Date.Day }} {{ index $.Site.Data.mois (printf "%d" .Date.Month) }} {{ .Date.Year }} (dernière modification le {{ .Lastmod.Day }} {{ index $.Site.Data.mois (printf "%d" .Lastmod.Month) }} {{ .Lastmod.Year }})

This technique extracts the day, month and year by specifying .Date.Day, .Date.Month, and .Date.Year, and uses the month number as a key, when indexing the month name data file.


You can define your menus for each language independently. The creation of a menu works analogous to earlier versions of Hugo, except that they have to be defined in their language-specific block in the configuration file:

defaultContentLanguage = "en"

weight = 0
languageName = "English"

url    = "/"
name   = "Home"
weight = 0

weight = 10
languageName = "Deutsch"

url    = "/"
name   = "Startseite"
weight = 0

The rendering of the main navigation works as usual. .Site.Menus will just contain the menu of the current language. Pay attention to the generation of the menu links. absLangURL takes care that you link to the correct locale of your website. Otherwise, both menu entries would link to the English version as the default content language that resides in the root directory.

    {{- $currentPage := . -}}
    {{ range .Site.Menus.main -}}
    <li class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}">
        <a href="{{ .URL | absLangURL }}">{{ .Name }}</a>
    {{- end }}

Missing translations

If a string does not have a translation for the current language, Hugo will use the value from the default language. If no default value is set, an empty string will be shown.

While translating a Hugo website, it can be handy to have a visual indicator of missing translations. The enableMissingTranslationPlaceholders configuration option will flag all untranslated strings with the placeholder [i18n] identifier, where identifier is the id of the missing translation.

{{% note %}} Hugo will generate your website with these missing translation placeholders. It might not be suited for production environments. {{% /note %}}

Multilingual Themes support

To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there is more than one language, URLs must meet the following criteria:

If there is more than one language defined, the LanguagePrefix variable will equal /en (or whatever your CurrentLanguage is). If not enabled, it will be an empty string and is therefore harmless for single-language Hugo websites.


Introduction to Hugo Templating

{{% note %}} The following is only a primer on Go templates. For an in-depth look into Go templates, check the official Go docs. {{% /note %}}

Go templates provide an extremely simple template language that adheres to the belief that only the most basic of logic belongs in the template or view layer.

Basic Syntax

Golang templates are HTML files with the addition of variables and functions. Golang template variables and functions are accessible within {{ }}.

Access a Predefined Variable

{{ foo }}

Parameters for functions are separated using spaces. The following example calls the add function with inputs of 1 and 2:

{{ add 1 2 }}

Methods and Fields are Accessed via dot Notation

Accessing the Page Parameter bar defined in a piece of content's front matter.

{{ }}

Parentheses Can be Used to Group Items Together

{{ if or (isset .Params "alt") (isset .Params "caption") }} Caption {{ end }}


Each Go template gets a data object. In Hugo, each template is passed a Page. See variables for more information.

This is how you access a Page variable from a template:

<title>{{ .Title }}</title>

Values can also be stored in custom variables and referenced later:

{{ $address := "123 Main St."}}
{{ $address }}

{{% warning %}} Variables defined inside if conditionals and similar are not visible on the outside. See

Hugo has created a workaround for this issue in Scratch.

{{% /warning %}}


Go templates only ship with a few basic functions but also provide a mechanism for applications to extend the original set.

Hugo template functions provide additional functionality specific to building websites. Functions are called by using their name followed by the required parameters separated by spaces. Template functions cannot be added without recompiling Hugo.

Example 1: Adding Numbers

{{ add 1 2 }}
=> 3

Example 2: Comparing Numbers

{{ lt 1 2 }}
=> true (i.e., since 1 is less than 2)

Note that both examples make us of Go template's math functions.

{{% note "Additional Boolean Operators" %}} There are more boolean operators than those listed in the Hugo docs in the Golang template documentation. {{% /note %}}


When including another template, you will pass to it the data it will be able to access. To pass along the current context, please remember to include a trailing dot. The templates location will always be starting at the /layout/ directory within Hugo.

Template and Partial Examples

{{ template "partials/header.html" . }}

Starting with Hugo v0.12, you may also use the partial call for partial templates:

{{ partial "header.html" . }}


Go templates provide the most basic iteration and conditional logic.


Just like in Go, the Go templates make heavy use of range to iterate over a map, array, or slice. The following are different examples of how to use range.

Example 1: Using Context

{{ range array }}
    {{ . }}
{{ end }}

Example 2: Declaring Value => Variable name

{{range $element := array}}
    {{ $element }}
{{ end }}

Example 3: Declaring Key-Value Variable Name

{{range $index, $element := array}}
   {{ $index }}
   {{ $element }}
{{ end }}


if, else, with, or, and and provide the framework for handling conditional logic in Go Templates. Like range, each statement is closed with an {{end}}.

Go Templates treat the following values as false:

  • false
  • 0
  • any zero-length array, slice, map, or string

Example 1: if

{{ if isset .Params "title" }}<h4>{{ index .Params "title" }}</h4>{{ end }}

Example 2: ifelse

{{ if isset .Params "alt" }}
    {{ index .Params "alt" }}
    {{ index .Params "caption" }}
{{ end }}

Example 3: and & or

{{ if and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}}

Example 4: with

An alternative way of writing "if" and then referencing the same value is to use "with" instead. with rebinds the context . within its scope and skips the block if the variable is absent.

The first example above could be simplified as:

{{ with .Params.title }}<h4>{{ . }}</h4>{{ end }}

Example 5: ifelse if

{{ if isset .Params "alt" }}
    {{ index .Params "alt" }}
{{ else if isset .Params "caption" }}
    {{ index .Params "caption" }}
{{ end }}


One of the most powerful components of Go templates is the ability to stack actions one after another. This is done by using pipes. Borrowed from Unix pipes, the concept is simple: each pipeline's output becomes the input of the following pipe.

Because of the very simple syntax of Go templates, the pipe is essential to being able to chain together function calls. One limitation of the pipes is that they can only work with a single value and that value becomes the last parameter of the next pipeline.

A few simple examples should help convey how to use the pipe.

Example 1: shuffle

The following two examples are functionally the same:

{{ shuffle (seq 1 5) }}
{{ (seq 1 5) | shuffle }}

Example 2: index

The following accesses the page parameter called "disqus_url" and escapes the HTML. This example also uses the index function, which is built into Go templates:

{{ index .Params "disqus_url" | html }}

Example 3: or with isset

{{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr") }}
Stuff Here
{{ end }}

Could be rewritten as

{{ if isset .Params "caption" | or isset .Params "title" | or isset .Params "attr" }}
Stuff Here
{{ end }}

Example 4: Internet Explorer Conditional Comments

By default, Go Templates remove HTML comments from output. This has the unfortunate side effect of removing Internet Explorer conditional comments. As a workaround, use something like this:

{{ "<!--[if lt IE 9]>" | safeHTML }}
  <script src="html5shiv.js"></script>
{{ "<![endif]-->" | safeHTML }}

Alternatively, you can use the backtick (`) to quote the IE conditional comments, avoiding the tedious task of escaping every double quotes (") inside, as demonstrated in the examples in the Go text/template documentation:

{{ `<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->` | safeHTML }}

Context (aka "the dot")

The most easily overlooked concept to understand about Go templates is that {{ . }} always refers to the current context. In the top level of your template, this will be the data set made available to it. Inside of an iteration, however, it will have the value of the current item in the loop; i.e., {{ . }} will no longer refer to the data available to the entire page. If you need to access page-level data (e.g., page params set in front matter) from within the loop, you will likely want to do one of the following:

1. Define a Variable Independent of Context

The following shows how to define a variable independent of the context.

{{< code file="tags-range-with-page-variable.html" >}} {{ $title := .Site.Title }}

    {{ range .Params.tags }}
  • {{ . }} - {{ $title }}
  • {{ end }}
{{< /code >}}

{{% note %}} Notice how once we have entered the loop (i.e. range), the value of {{ . }} has changed. We have defined a variable outside of the loop ({{$title}}) that we've assigned a value so that we have access to the value from within the loop as well. {{% /note %}}

2. Use $. to Access the Global Context

$ has special significance in your templates. $ is set to the starting value of . ("the dot") by default. This is a documented feature of Go text/template. This means you have access to the global context from anywhere. Here is an equivalent example of the preceding code block but now using $ to grab .Site.Title from the global context:

{{< code file="range-through-tags-w-global.html" >}}

    {{ range .Params.tags }}
  • {{ . }} - {{ $.Site.Title }}
  • {{ end }}
{{< /code >}}

{{% warning "Don't Redefine the Dot" %}} The built-in magic of $ would cease to work if someone were to mischievously redefine the special character; e.g. {{ $ := .Site }}. Don't do it. You may, of course, recover from this mischief by using {{ $ := . }} in a global context to reset $ to its default value. {{% /warning %}}


Go 1.6 includes the ability to trim the whitespace from either side of a Go tag by including a hyphen (-) and space immediately beside the corresponding {{ or }} delimiter.

For instance, the following Go template will include the newlines and horizontal tab in its HTML output:

  {{ .Title }}

Which will output:

  Hello, World!

Leveraging the - in the following example will remove the extra white space surrounding the .Title variable and remove the newline:

  {{- .Title -}}

Which then outputs:

<div>Hello, World!</div>

Go considers the following characters whitespace:

  • space
  • horizontal tab
  • carriage return
  • newline

Hugo Parameters

Hugo provides the option of passing values to your template layer through your site configuration (i.e. for site-wide values) or through the metadata of each specific piece of content (i.e. the front matter). You can define any values of any type and use them however you want in your templates, as long as the values are supported by the front matter format specified via metaDataFormat in your configuration file.

Use Content (Page) Parameters

You can provide variables to be used by templates in individual content's front matter.

An example of this is used in the Hugo docs. Most of the pages benefit from having the table of contents provided, but sometimes the table of contents doesn't make a lot of sense. We've defined a notoc variable in our front matter that will prevent a table of contents from rendering when specifically set to true.

Here is the example front matter:

title: Roadmap
lastmod: 2017-03-05
date: 2013-11-18
notoc: true

Here is an example of corresponding code that could be used inside a toc.html partial template:

{{< code file="layouts/partials/toc.html" download="toc.html" >}} {{ if not .Params.notoc }}


{{.TableOfContents}} {{end}} {{< /code >}}

We want the default behavior to be for pages to include a TOC unless otherwise specified. This template checks to make sure that the notoc: field in this page's front matter is not true.

Use Site Configuration Parameters

You can arbitrarily define as many site-level parameters as you want in your site's configuration file. These parameters are globally available in your templates.

For instance, you might declare the following:

{{< code file="config.yaml" >}} params: copyrighthtml: "Copyright © 2017 John Doe. All Rights Reserved." twitteruser: "spf13" sidebarrecentlimit: 5 {{< /code >}}

Within a footer layout, you might then declare a <footer> that is only rendered if the copyrighthtml parameter is provided. If it is provided, you will then need to declare the string is safe to use via the safeHTML function so that the HTML entity is not escaped again. This would let you easily update just your top-level config file each January 1st, instead of hunting through your templates.

{{if .Site.Params.copyrighthtml}}<footer>
<div class="text-center">{{.Site.Params.CopyrightHTML | safeHTML}}</div>

An alternative way of writing the "if" and then referencing the same value is to use with instead. with rebinds the context (.) within its scope and skips the block if the variable is absent:

{{< code file="layouts/partials/twitter.html" >}} {{with .Site.Params.twitteruser}}

{{end}} {{< /code >}}

Finally, you can pull "magic constants" out of your layouts as well. The following uses the first function, as well as the .RelPermalink page variable and the .Site.Pages site variable.

  <h1>Recent Posts</h1>
  {{- range first .Site.Params.SidebarRecentLimit .Site.Pages -}}
    <li><a href="{{.RelPermalink}}">{{.Title}}</a></li>
  {{- end -}}

Example: Show Only Upcoming Events

Go allows you to do more than what's shown here. Using Hugo's where function and Go built-ins, we can list only the items from content/events/ whose date (set in a content file's front matter) is in the future. The following is an example partial template:

{{< code file="layouts/partials/upcoming-events.html" download="upcoming-events.html" >}}

Upcoming Events

    {{ range where .Data.Pages.ByDate "Section" "events" }} {{ if ge .Date.Unix .Now.Unix }}
  • {{ .Type | title }} — {{ .Title }} on {{ .Date.Format "2 January at 3:04pm" }} at {{ }}
  • {{ end }} {{ end }}
{{< /code >}}

Hugo's Lookup Order

Before creating your templates, it's important to know how Hugo looks for files within your project's directory structure.

Hugo uses a prioritized list called the lookup order as it traverses your layouts folder in your Hugo project looking for the appropriate template to render your content.

The template lookup order is an inverted cascade: if template A isn’t present or specified, Hugo will look to template B. If template B isn't present or specified, Hugo will look for template C...and so on until it reaches the _default/ directory for your project or theme. In many ways, the lookup order is similar to the programming concept of a switch statement without fallthrough.

The power of the lookup order is that it enables you to craft specific layouts and keep your templating DRY.

{{% note %}} Most Hugo websites will only need the default template files at the end of the lookup order (i.e. _default/*.html). {{% /note %}}

Lookup Orders

The respective lookup order for each of Hugo's templates has been defined throughout the Hugo docs:

Template Lookup Examples

The lookup order is best illustrated through examples. The following shows you the process Hugo uses for finding the appropriate template to render your single page templates, but the concept holds true for all templates in Hugo.

  1. The project is using the theme mytheme (specified in the project's configuration).
  2. The layouts and content directories for the project are as follows:
├── content
│   ├── events
│   │   ├──
│   │   └──
│   └── posts
│       ├──
│       └──
├── layouts
│   ├── _default
│   │   └── single.html
│   ├── posts
│   │   └── single.html
│   └── reviews
│       └── reviewarticle.html
└── themes
    └── mytheme
        └── layouts
            ├── _default
            │   ├── list.html
            │   └── single.html
            └── posts
                ├── list.html
                └── single.html

Now we can look at the front matter for the three content ( files.

{{% note %}} Only three of the four markdown files in the above project are subject to the single page lookup order. is a specific kind in Hugo. Whereas,, and are all of kind page, all files in a Hugo project are used to add content and front matter to list pages. In this example, events/ will render according to its section template and respective lookup order. {{% /note %}}


{{< code file="content/posts/" copy="false" >}}

title: My First Post date: 2017-02-19 description: This is my first post.

{{< /code >}}

When building your site, Hugo will go through the lookup order until it finds what it needs for

  2. /layouts/posts/UNSPECIFIED.html
  3. /layouts/UNSPECIFIED/single.html
  4. /layouts/posts/single.html
  5. /layouts/_default/single.html
  6. /themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
  7. /themes/<THEME>/layouts/posts/UNSPECIFIED.html
  8. /themes/<THEME>/layouts/UNSPECIFIED/single.html
  9. /themes/<THEME>/layouts/posts/single.html
  10. /themes/<THEME>/layouts/_default/single.html

Notice the term UNSPECIFIED rather than UNDEFINED. If you don't tell Hugo the specific type and layout, it makes assumptions based on sane defaults. does not specify a content type in its front matter. Therefore, Hugo assumes the content type and section (i.e. posts, which is defined by file location) are one in the same. (Read more on sections.) also does not specify a layout in its front matter. Therefore, Hugo assumes that, which is of type page and a single piece of content, should default to the next occurrence of a single.html template in the lookup (#4).


{{< code file="content/posts/" copy="false" >}}

title: My Second Post date: 2017-02-21 description: This is my second post. type: review layout: reviewarticle

{{< /code >}}

Here is the way Hugo traverses the single-page lookup order for

  1. /layouts/review/reviewarticle.html
  2. /layouts/posts/reviewarticle.html
  3. /layouts/review/single.html
  4. /layouts/posts/single.html
  5. /layouts/_default/single.html
  6. /themes/<THEME>/layouts/review/reviewarticle.html
  7. /themes/<THEME>/layouts/posts/reviewarticle.html
  8. /themes/<THEME>/layouts/review/single.html
  9. /themes/<THEME>/layouts/posts/single.html
  10. /themes/<THEME>/layouts/_default/single.html

The front matter in specifies the content type (i.e. review) as well as the layout (i.e. reviewarticle). Hugo finds the layout it needs at the top level of the lookup (#1) and does not continue to search through the other templates.

{{% note "Type and not Types" %}} Notice that the directory for the template for is review and not reviews. This is because type is always singular when defined in front matter. {{% /note%}}


{{< code file="content/events/" copy="false" >}}

title: My First date: 2017-02-21 description: This is an upcoming event..

{{< /code >}}

Here is the way Hugo traverses the single-page lookup order for

  2. /layouts/events/UNSPECIFIED.html
  3. /layouts/UNSPECIFIED/single.html
  4. /layouts/events/single.html
  5. /layouts/_default/single.html
  6. /themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
  7. /themes/<THEME>/layouts/events/UNSPECIFIED.html
  8. /themes/<THEME>/layouts/UNSPECIFIED/single.html
  9. /themes/<THEME>/layouts/events/single.html
  10. /themes/<THEME>/layouts/_default/single.html

{{% note %}} is significant because it demonstrates the role of the lookup order in Hugo themes. Both the root project directory and the mytheme themes directory have a file at _default/single.html. Understanding this order allows you to customize Hugo themes by creating template files with identical names in your project directory that step in front of theme template files in the lookup. This allows you to customize the look and feel of your website while maintaining compatibility with the theme's upstream. {{% /note %}}

Custom Output Formats

This page describes how to properly configure your site with the media types and output formats, as well as where to create your templates for your custom outputs.

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:

{{< datatable "media" "types" "type" "suffix" >}}


  • It is possible to add custom media types or change the defaults; e.g., if you want to change the suffix for text/html to asp.
  • 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/custom 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 configuration, 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 Hugo's built-in output formats:

{{< datatable "output" "formats" "name" "mediaType" "path" "baseName" "rel" "protocol" "isPlainText" "isHTML" "noUgly">}}

  • 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 above table, the best example of this is AMP vs. HTML. AMP has the value amp for Path so it doesn't overwrite the HTML version; e.g. we can now have both /index.html and /amp/index.html.
  • The MediaType must match the Type of an already defined media type.
  • You can define new output formats or redefine built-in output formats; e.g., if you want to put AMP pages in a different path.

To add or modify an output format, define it in an outputFormats section in your site's configuration file, either for all sites or for a given language.

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

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

Configure Output Formats

The following is the full list of configuration options for output formats and their default values:

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 (homepage, 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 formats; e.g., page aliases.

noUgly : used to turn off ugly URLs If uglyURLs is set to true in your site. Default: false.

notAlternative : enable if it doesn't make sense to include this format in an AlternativeOutputFormats format listing on Page (e.g., with CSS). Note that we use the term alternative and not alternate here, as it does not necessarily replace the other format. Default: false.

Output Formats for Pages

A Page in Hugo can be rendered to multiple representations on the file system. By default, all pages will render as HTML with some of them also as RSS (homepage, 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.toml:

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

Example from site config.yml:

  home: ["HTML", "AMP", "RSS"]
  page: ["HTML"]
  • The output definition is per Page Kind (i.e, page, home, section, taxonomy, or taxonomyTerm).
  • The names used must match the Name of a defined Output Format.
  • Any Kind without a definition will default to HTML.
  • These can be overridden per Page in the front matter of content files.
  • Output formats are case insensitive.

The following is an example of YAML front matter in a content file that defines output formats for the rendered Page:

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

Link to Output Formats

Each Page has both an .OutputFormats (all formats, including the current) and an .AlternativeOutputFormats variable, the latter of which is useful for creating a link rel list in your site's <head>:

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

Note that .Permalink and .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

A new output format needs a corresponding template in order to render anything useful.

{{% note %}} The key distinction for Hugo versions 0.20 and newer is that Hugo looks at an output format's Name and MediaType's Suffix when choosing the template used to render a given Page. {{% /note %}}

The following table shows examples of different output formats, the suffix used, and Hugo's respective template lookup order. All of the examples in the table can:

{{< datatable "output" "layouts" "Example" "OutputFormat" "Suffix" "Template Lookup Order" >}}

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. The pattern is as follows:

[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" . }}

Base Templates and Blocks

The block keyword allows you to define the outer shell of your pages' one or more master template(s) and then fill in or override portions as necessary.

Base Template Lookup Order

The lookup order for base templates is as follows:

  1. /layouts/section/<TYPE>-baseof.html
  2. /themes/<THEME>/layouts/section/<TYPE>-baseof.html
  3. /layouts/<TYPE>/baseof.html
  4. /themes/<THEME>/layouts/<TYPE>/baseof.html
  5. /layouts/section/baseof.html
  6. /themes/<THEME>/layouts/section/baseof.html
  7. /layouts/_default/post-baseof.html
  8. /themes/<THEME>/layouts/_default/post-baseof.html
  9. /layouts/_default/baseof.html
  10. /themes/<THEME>/layouts/_default/baseof.html

Variables are denoted by capitalized text set within <>. Note that Hugo's default behavior is for type to inherit from section unless otherwise specified.

Example Base Template Lookup Order

As an example, let's assume your site is using a theme called "mytheme" when rendering the section list for a post section. Hugo picks layout/section/post.html as the template for rendering the section. The {{define}} block in this template tells Hugo that the template is an extension of a base template.

Here is the lookup order for the post base template:

  1. /layouts/section/post-baseof.html
  2. /themes/mytheme/layouts/section/post-baseof.html
  3. /layouts/post/baseof.html
  4. /themes/mytheme/layouts/post/baseof.html
  5. /layouts/section/baseof.html
  6. /themes/mytheme/layouts/section/baseof.html
  7. /layouts/_default/post-baseof.html
  8. /themes/mytheme/layouts/_default/post-baseof.html
  9. /layouts/_default/baseof.html
  10. /themes/mytheme/layouts/_default/baseof.html

Define the Base Template

The following defines a simple base template at _default/baseof.html. As a default template, it is the shell from which all your pages will be rendered unless you specify another *baseof.html closer to the beginning of the lookup order.

{{< code file="layouts/_default/baseof.html" download="baseof.html" >}}

<title>{{ block "title" . }} {{ .Site.Title }} {{ end }}</title> {{ block "main" . }} {{ end }} {{ block "footer" . }} {{ end }} {{< /code >}}

Override the Base Template

From the above base template, you can define a default list template. The default list template will inherit all of the code defined above and can then implement its own "main" block from:

{{< code file="layouts/_default/list.html" download="list.html" >}} {{ define "main" }}


{{ range .Data.Pages }}

{{ .Title }}

{{ .Content }} {{ end }} {{ end }} {{< /code >}}

This replaces the contents of our (basically empty) "main" block with something useful for the list template. In this case, we didn't define a "title" block, so the contents from our base template remain unchanged in lists.

{{% warning %}} Code that you put outside the block definitions can break your layout. This even includes HTML comments. For example:

<!-- Seemingly harmless HTML comment..that will break your layout at build -->
{{ define "main" }}
...your code here
{{ end }}

See this thread from the Hugo discussion forums. {{% /warning %}}

The following shows how you can override both the "main" and "title" block areas from the base template with code unique to your default single page template:

{{< code file="layouts/_default/single.html" download="single.html" >}} {{ define "title" }}

{{ .Title }} – {{ .Site.Title }} {{ end }} {{ define "main" }}

{{ .Title }}

{{ .Content }} {{ end }} {{< /code >}}

Lists of Content in Hugo

What is a List Page Template?

A list page template is a template used to render multiple pieces of content in a single HTML page. The exception to this rule is the homepage, which is still a list but has its own dedicated template.

Hugo uses the term list in its truest sense; i.e. a sequential arrangement of material, especially in alphabetical or numerical order. Hugo uses list templates on any output HTML page where content is traditionally listed:

The idea of a list page comes from the hierarchical mental model of the web and is best demonstrated visually:

Image demonstrating a hierarchical website sitemap.

List Defaults

Default Templates

Since section lists and taxonomy lists (N.B., not taxonomy terms lists) are both lists with regards to their templates, both have the same terminating default of _default/list.html or themes/<THEME>/layouts/_default/list.html in their lookup order. In addition, both section lists and taxonomy lists have their own default list templates in _default:

Default Section Templates

  1. layouts/_default/section.html
  2. layouts/_default/list.html

Default Taxonomy List Templates

  1. layouts/_default/taxonomy.html
  2. themes/<THEME>/layouts/_default/taxonomy.html

Add Content and Front Matter to List Pages

Since v0.18, everything in Hugo is a Page. This means list pages and the homepage can have associated content files (i.e. that contain page metadata (i.e., front matter) and content.

This new model allows you to include list-specific front matter via .Params and also means that list templates (e.g., layouts/_default/list.html) have access to all page variables.

{{% note %}} It is important to note that all content files will render according to a list template and not according to a single page template. {{% /note %}}

Example Project Directory

The following is an example of a typical Hugo project directory's content:

├── content
|   ├── post
|   |   ├──
|   |   ├──
|   |   └──
|   └── quote
|   |   ├──
|   |   └──

Using the above example, let's assume you have the following in content/post/

{{< code file="content/post/" >}}

title: My Golang Journey date: 2017-03-23 publishdate: 2017-03-24

I decided to start learning Golang in March 2017.

Follow my journey through this new blog. {{< /code >}}

You can now access this's' content in your list template:

{{< code file="layouts/_default/list.html" download="list.html" >}} {{ define "main" }}


{{.Content}} {{ end }} {{< /code >}}

This above will output the following HTML:

{{< code file="" copy="false" >}}

My Golang Journey

I decided to start learning Golang in March 2017.

Follow my journey through this new blog.

{{< /code >}}

List Pages Without

You do not have to create an file for every list page (i.e. section, taxonomy, taxonomy terms, etc) or the homepage. If Hugo does not find an within the respective content section when rendering a list template, the page will be created but with no {{.Content}} and only the default values for .Title etc.

Using this same layouts/_default/list.html template and applying it to the the quotes section above will render the following output. Note that quotes does not have an file to pull from:

{{< code file="" copy="false" >}}


{{< /code >}}

{{% note %}} The default behavior of Hugo is to pluralize list titles; hence the inflection of the quote section to "Quotes" when called with the .Title page variable. You can change this via the pluralizeListTitles directive in your site configuration. {{% /note %}}

Example List Templates

Section Template

This list template has been modified slightly from a template originally used in It makes use of partial templates for the chrome of the rendered page rather than using a base template The examples that follow also use the content view templates li.html or summary.html.

{{< code file="layouts/section/post.html" >}} {{ partial "header.html" . }} {{ partial "subheader.html" . }}

{{ .Title }}

    {{ range .Data.Pages }} {{ .Render "li"}} {{ end }}
{{ partial "footer.html" . }} {{< /code >}}

Taxonomy Template

{{< code file="layouts/_default/taxonomies.html" download="taxonomies.html" >}} {{ define "main" }}

{{ .Title }}

{{ range .Data.Pages }} {{ .Render "summary"}} {{ end }}
{{ end }} {{< /code >}}

Order Content

Hugo lists render the content based on metadata you provide in front matter. In addition to sane defaults, Hugo also ships with multiple methods to make quick work of ordering content inside list templates:

Default: Weight > Date > LinkTitle > FilePath

{{< code file="layouts/partials/default-order.html" >}}

    {{ range .Data.Pages }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Weight

{{< code file="layouts/partials/by-weight.html" >}}

    {{ range .Data.Pages.ByWeight }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Date

{{< code file="layouts/partials/by-date.html" >}}

    {{ range .Data.Pages.ByDate }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Publish Date

{{< code file="layouts/partials/by-publish-date.html" >}}

    {{ range .Data.Pages.ByPublishDate }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Expiration Date

{{< code file="layouts/partials/by-expiry-date.html" >}}

    {{ range .Data.Pages.ByExpiryDate }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Last Modified Date

{{< code file="layouts/partials/by-last-mod.html" >}}

    {{ range .Data.Pages.ByLastmod }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Length

{{< code file="layouts/partials/by-length.html" >}}

    {{ range .Data.Pages.ByLength }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Title

{{< code file="layouts/partials/by-title.html" >}}

    {{ range .Data.Pages.ByTitle }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Link Title

{{< code file="layouts/partials/by-link-title.html" >}}

    {{ range .Data.Pages.ByLinkTitle }}
  • {{ .LinkTitle }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Parameter

Order based on the specified front matter parameter. Content that does not have the specified front matter field will use the site's .Site.Params default. If the parameter is not found at all in some entries, those entries will appear together at the end of the ordering.

{{< code file="layouts/partials/by-rating.html" >}}

{{ range (.Data.Pages.ByParam "rating") }}

{{ end }} {{< /code >}}

If the targeted front matter field is nested beneath another field, you can access the field using dot notation.

{{< code file="layouts/partials/by-nested-param.html" >}} {{ range (.Data.Pages.ByParam "author.last_name") }}

{{ end }} {{< /code >}}

Reverse Order

Reversing order can be applied to any of the above methods. The following uses ByDate as an example:

{{< code file="layouts/partials/by-date-reverse.html" >}}

    {{ range .Data.Pages.ByDate.Reverse }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

Group Content

Hugo provides some functions for grouping pages by Section, Type, Date, etc.

By Page Field

{{< code file="layouts/partials/by-page-field.html" >}}

{{ range .Data.Pages.GroupBy "Section" }}

{{ .Key }}

    {{ range .Pages }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

In the above example, you may want {{.Title}} to point the title field you have added to your file instead. You can access this value using the .GetPage function:

{{< code file="layouts/partials/by-page-field.html" >}}

{{ range .Data.Pages.GroupBy "Section" }}

{{ with $.Site.GetPage "section" .Key }}


{{ else }}

{{ .Key | title }}

{{ end }}
    {{ range .Pages }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

By Date

{{< code file="layouts/partials/by-page-date.html" >}}

{{ range .Data.Pages.GroupByDate "2006-01" }}

{{ .Key }}

    {{ range .Pages }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

By Publish Date

{{< code file="layouts/partials/by-page-publish-date.html" >}}

{{ range .Data.Pages.GroupByPublishDate "2006-01" }}

{{ .Key }}

    {{ range .Pages }}
  • {{ .Title }}
    {{ .PublishDate.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

By Page Parameter

{{< code file="layouts/partials/by-page-param.html" >}}

{{ range .Data.Pages.GroupByParam "param_key" }}

{{ .Key }}

    {{ range .Pages }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

By Page Parameter in Date Format

The following template takes grouping by date a step further and uses Golang's layout string. See the Format function for more examples of how to use Golang's layout string to format dates in Hugo.

{{< code file="layouts/partials/by-page-param-as-date.html" >}}

{{ range .Data.Pages.GroupByParamDate "param_key" "2006-01" }}

{{ .Key }}

    {{ range .Pages }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

Reverse Key Order

Ordering of groups is performed by keys in alphanumeric order (A–Z, 1–100) and in reverse chronological order (i.e., with the newest first) for dates.

While these are logical defaults, they are not always the desired order. There are two different syntaxes to change Hugo's default ordering for groups, both of which work the same way.

1. Adding the Reverse Method

{{ range (.Data.Pages.GroupBy "Section").Reverse }}
{{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}

2. Providing the Alternate Direction

{{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
{{ range .Data.Pages.GroupBy "Section" "desc" }}

Order Within Groups

Because Grouping returns a {{.Key}} and a slice of pages, all of the ordering methods listed above are available.

Here is the ordering for the example that follows:

  1. Content is grouped by month according to the date field in front matter.
  2. Groups are listed in ascending order (i.e., the oldest groups first)
  3. Pages within each respective group are ordered alphabetically according to the title.

{{< code file="layouts/partials/by-group-by-page.html" >}} {{ range .Data.Pages.GroupByDate "2006-01" "asc" }}

{{ .Key }}

    {{ range .Pages.ByTitle }}
  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{ end }} {{< /code >}}

Filter and Limiting Lists

Sometimes you only want to list a subset of the available content. A common is to only display “Posts” on blog's homepage. You can accomplish this with the where function.


where works in a similar manner to the where keyword in SQL. It selects all elements of the array or slice that match the provided field and value. where takes three arguments:

  1. array or slice of maps or structs
  2. key or field name
  3. match value

{{< code file="layouts/_default/.html" >}} {{ range where .Data.Pages "Section" "post" }} {{ .Content }} {{ end }} {{< /code >}}

You can see more examples in the functions documentation for where.


first works in a similar manner to the limit keyword in SQL. It reduces the array to only the first N elements. It takes the array and number of elements as input. first takes two arguments:

  1. array or slice of maps or structs
  2. number of elements

{{< code file="layout/_default/section.html" >}} {{ range first 10 .Data.Pages }} {{ .Render "summary" }} {{ end }} {{< /code >}}

first and where Together

Using first and where together can be very powerful:

{{< code file="first-and-where-together.html" >}}

{{ range first 5 (where .Data.Pages "Section" "post").ByTitle }} {{ .Content }} {{ end }} {{< /code >}}

Ordere and Grouping Hugo Lists

In Hugo, A list template is any template that will be used to render multiple pieces of content in a single HTML page.

Example List Templates

Section Template

This list template is used for It makes use of partial templates. All examples use a view called either "li" or "summary."

{{< code file="layouts/section/post.html" >}} {{ partial "header.html" . }} {{ partial "subheader.html" . }}

{{ .Title }}

    {{ range .Data.Pages }} {{ .Render "li"}} {{ end }}
{{ partial "footer.html" . }} {{< /code >}}

Taxonomy Template

{{< code file="layouts/_default/taxonomies.html" download="taxonomies.html" >}} {{ define "main" }}

{{ .Title }}

{{ range .Data.Pages }} {{ .Render "summary"}} {{ end }}
{{ end }} {{< /code >}}

Order Content

Hugo lists render the content based on metadata provided in the front matter..

Here are a variety of different ways you can order the content items in your list templates:

Default: Weight > Date

{{< code file="layouts/partials/order-default.html" >}}

    {{ range .Data.Pages }}
  • {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }}
{{< /code >}}

By Weight

{{< code file="layouts/partials/by-weight.html" >}} {{ range .Data.Pages.ByWeight }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Date

    {{< code file="layouts/partials/by-date.html" >}} {{ range .Data.Pages.ByDate }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Publish Date

    {{< code file="layouts/partials/by-publish-date.html" >}} {{ range .Data.Pages.ByPublishDate }}

  • {{ .Title }}
    {{ .PublishDate.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Expiration Date

    {{< code file="layouts/partials/by-expiry-date.html" >}} {{ range .Data.Pages.ByExpiryDate }}

  • {{ .Title }}
    {{ .ExpiryDate.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Last Modified Date

    {{< code file="layouts/partials/by-last-mod.html" >}} {{ range .Data.Pages.ByLastmod }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Length

    {{< code file="layouts/partials/by-length.html" >}} {{ range .Data.Pages.ByLength }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Title

    {{< code file="layouts/partials/by-title.html" >}} {{ range .Data.Pages.ByTitle }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Link Title

    {{< code file="layouts/partials/by-link-title.html" >}} {{ range .Data.Pages.ByLinkTitle }}

  • {{ .LinkTitle }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    By Parameter

    Order based on the specified front matter parameter. Content that does not have the specified front matter field will use the site's .Site.Params default. If the parameter is not found at all in some entries, those entries will appear together at the end of the ordering.

    The below example sorts a list of posts by their rating.

    {{< code file="layouts/partials/by-rating.html" >}} {{ range (.Data.Pages.ByParam "rating") }}

    {{ end }} {{< /code >}}

    If the front matter field of interest is nested beneath another field, you can also get it:

    {{< code file="layouts/partials/by-nested-param.html" >}} {{ range (.Data.Pages.ByParam "author.last_name") }}

    {{ end }} {{< /code >}}

    Reverse Order

    Reversing order can be applied to any of the above methods. The following uses ByDate as an example:

    {{< code file="layouts/partials/by-date-reverse.html" >}} {{ range .Data.Pages.ByDate.Reverse }}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{ end }} {{< /code >}}

    Group Content

    Hugo provides some functions for grouping pages by Section, Type, Date, etc.

    By Page Field

    {{< code file="layouts/partials/by-page-field.html" >}} {{ range .Data.Pages.GroupBy "Section" }}

    {{ .Key }}

      {{ range .Pages }}
    • {{ .Title }}
      {{ .Date.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    By Page date

    {{< code file="layouts/partials/by-page-date.html" >}} {{ range .Data.Pages.GroupByDate "2006-01" }}

    {{ .Key }}

      {{ range .Pages }}
    • {{ .Title }}
      {{ .Date.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    By Page publish date

    {{< code file="layouts/partials/by-page-publish-date.html" >}} {{ range .Data.Pages.GroupByPublishDate "2006-01" }}

    {{ .Key }}

      {{ range .Pages }}
    • {{ .Title }}
      {{ .PublishDate.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    By Page Param

    {{< code file="layouts/partials/by-page-param.html" >}} {{ range .Data.Pages.GroupByParam "param_key" }}

    {{ .Key }}

      {{ range .Pages }}
    • {{ .Title }}
      {{ .Date.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    By Page Param in Date Format

    {{< code file="layouts/partials/by-page-param-as-date.html" >}} {{ range .Data.Pages.GroupByParamDate "param_key" "2006-01" }}

    {{ .Key }}

      {{ range .Pages }}
    • {{ .Title }}
      {{ .Date.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    Reverse Key Order

    The ordering of the groups is performed by keys in alphanumeric order (A–Z, 1–100) and in reverse chronological order (newest first) for dates.

    While these are logical defaults, they are not always the desired order. There are two different syntaxes to change the order, both of which work the same way. You can use your preferred syntax.

    Reverse Method

    {{ range (.Data.Pages.GroupBy "Section").Reverse }}
    {{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}

    Provide the Alternate Direction

    {{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
    {{ range .Data.Pages.GroupBy "Section" "desc" }}

    Order Within Groups

    Because Grouping returns a {{.Key}} and a slice of pages, all of the ordering methods listed above are available.

    In the following example, groups are ordered chronologically and then content within each group is ordered alphabetically by title.

    {{< code file="layouts/partials/by-group-by-page.html" >}} {{ range .Data.Pages.GroupByDate "2006-01" "asc" }}

    {{ .Key }}

      {{ range .Pages.ByTitle }}
    • {{ .Title }}
      {{ .Date.Format "Mon, Jan 2, 2006" }}
    • {{ end }}
    {{ end }} {{< /code >}}

    Filter and Limiting Lists

    Sometimes you only want to list a subset of the available content. A common request is to only display “Posts” on the homepage. You can accomplish this with the where function.


    where works in a similar manner to the where keyword in SQL. It selects all elements of the array or slice that match the provided field and value. where takes three arguments:

    1. array or a slice of maps or structs
    2. key or field name
    3. match value

    {{< code file="layouts/_default/.html" >}} {{ range where .Data.Pages "Section" "post" }} {{ .Content }} {{ end }} {{< /code >}}


    first works in a similar manner to the limit keyword in SQL. It reduces the array to only the first N elements. It takes the array and number of elements as input. first takes two arguments:

    1. array or slice of maps or structs
    2. number of elements

    {{< code file="layout/_default/section.html" >}} {{ range first 10 .Data.Pages }} {{ .Render "summary" }} {{ end }} {{< /code >}}

    first and where Together

    Using first and where together can be very powerful:

    {{< code file="first-and-where-together.html" >}} {{ range first 5 (where .Data.Pages "Section" "post") }} {{ .Content }} {{ end }} {{< /code >}}

    Homepage Template

    Homepage is a Page and therefore has all the page variables and site variables available for use.

    {{% note "The Only Required Template" %}} The homepage template is the only required template for building a site and therefore useful when bootstrapping a new site and template. It is also the only required template if you are developing a single-page website. {{% /note %}}

    Homepage Template Lookup Order

    The lookup order for the homepage template is as follows:

    1. /layouts/index.html
    2. /layouts/_default/list.html
    3. /themes/<THEME>/layouts/index.html
    4. /themes/<THEME>/layouts/_default/list.html

    Add Content and Front Matter to the Homepage

    The homepage, similar to other list pages in Hugo, accepts content and front matter from an file. This file should live at the root of your content folder (i.e., content/ You can then add body copy and metadata to your homepage the way you would any other content file.

    See the homepage template below or Content Organization for more information on the role of in adding content and front matter to list pages.

    .Data.Pages on the Homepage

    In addition to the standard page variables, the homepage template has access to all site content via .Data.Pages.

    Example Homepage Template

    The following is an example of a homepage template that uses partial, base templates, and a content file at content/ to populate the {{.Title}} and {{Content}} page variables.

    {{< code file="layouts/index.html" download="index.html" >}} {{ define "main" }}


    {{ with .Params.subtitle }} {{.}} {{ end }}
    {{ range first 10 .Data.Pages }} {{ .Render "summary"}} {{ end }}
    {{ end }} {{< /code >}}

    Section Page Templates

    Add Content and Front Matter to Section Templates

    To effectively leverage section page templates, you should first understand Hugo's content organization and, specifically, the purpose of for adding content and front matter to section and other list pages.

    Section Template Lookup Order

    The lookup order for section templates is as follows:

    1. /layouts/section/<SECTION>.html
    2. /layouts/<SECTION>/list.html
    3. /layouts/_default/section.html
    4. /layouts/_default/list.html
    5. /themes/<THEME>/layouts/section/<SECTION>.html
    6. /themes/<THEME>/layouts/<SECTION>/list.html
    7. /themes/<THEME>/layouts/_default/section.html
    8. /themes/<THEME>/layouts/_default/list.html

    .Site.GetPage with Sections

    Every Page in Hugo has a .Kind attribute. Kind can easily be combined with the where function in your templates to create kind-specific lists of content. This method is ideal for creating lists, but there are times where you may want to fetch just the index page of a single section via the section's path.

    The .GetPage function looks up an index page of a given Kind and path.

    {{% note %}} .GetPage is not currently supported to grab single content files but may be supported in the future. {{% /note %}}

    You can call .Site.GetPage with two arguments: kind and kind value.

    These are the valid values for 'kind':

    1. home
    2. section
    3. taxonomy
    4. taxonomyTerm

    Example: Creating a Default Section Template

    {{< code file="layouts/_default/section.html" download="section.html" >}} {{ define "main" }}

    {{ .Content }}
      {{ range .Paginator.Pages }}
    • {{.Title}}
      {{ partial "summary.html" . }}
    • {{ end }}
    {{ partial "pagination.html" . }} {{ end }} {{< /code >}}

    Example: Using .Site.GetPage

    The .Site.GetPage example that follows assumes the following project directory structure:

    └── content
        ├── blog
        │   ├── # "title: My Hugo Blog" in the front matter
        │   ├──
        │   ├──
        │   └──
        └── events #Note there is no file in "events"

    .Site.GetPage will return nil if no page is found. Therefore, if content/blog/ does not exist, the template will output the section name:

    <h1>{{ with .Site.GetPage "section" "blog" }}{{ .Title }}{{ end }}</h1>

    Since blog has a section index page with front matter at content/blog/, the above code will return the following result:

    <h1>My Hugo Blog</h1>

    If we try the same code with the events section, however, Hugo will default to the section title because there is no content/events/ from which to pull content and front matter:

    <h1>{{ with .Site.GetPage "section" "events" }}{{ .Title }}{{ end }}</h1>

    Which then returns the following:


    Taxonomy Templates

    Hugo includes support for user-defined groupings of content called taxonomies. Taxonomies are classifications that demonstrate logical relationships between content. See Taxonomies under Content Management if you are unfamiliar with how Hugo leverages this powerful feature.

    Hugo provides multiple ways to use taxonomies throughout your project templates:

    Taxonomy List Templates

    Taxonomy list page templates are lists and therefore have all the variables and methods available to list pages.

    Taxonomy List Template Lookup Order

    A taxonomy will be rendered at /PLURAL/TERM/ (e.g., according to the following lookup order:

    1. /layouts/taxonomy/<SINGULAR>.html
    2. /layouts/_default/taxonomy.html
    3. /layouts/_default/list.html
    4. /themes/<THEME>/layouts/taxonomy/<SINGULAR>.html
    5. /themes/<THEME>/layouts/_default/taxonomy.html
    6. /themes/<THEME>/layouts/_default/list.html

    Taxonomy Terms Template

    Taxonomy Terms Templates Lookup Order

    A taxonomy terms page will be rendered at<PLURALTAXONOMYNAME>/ (e.g., according to the following lookup order:

    1. /layouts/taxonomy/<SINGULAR>.terms.html
    2. /layouts/_default/terms.html
    3. /themes/<THEME>/layouts/taxonomy/<SINGULAR>.terms.html
    4. /themes/<THEME>/layouts/_default/terms.html

    {{% warning "The Taxonomy Terms Template has a Unique Lookup Order" %}} If Hugo does not find a terms template in layout/ or /themes/<THEME>/layouts/, Hugo will not render a taxonomy terms page. {{% /warning %}}

    Hugo makes a set of values and methods available on the various Taxonomy structures.

    Taxonomy Methods

    A Taxonomy is a map[string]WeightedPages.

    .Get(term) : Returns the WeightedPages for a term.

    .Count(term) : The number of pieces of content assigned to this term.

    .Alphabetical : Returns an OrderedTaxonomy (slice) ordered by Term.

    .ByCount : Returns an OrderedTaxonomy (slice) ordered by number of entries.


    Since Maps are unordered, an OrderedTaxonomy is a special structure that has a defined order.

    []struct {
        Name          string
        WeightedPages WeightedPages

    Each element of the slice has:

    .Term : The Term used.

    .WeightedPages : A slice of Weighted Pages.

    .Count : The number of pieces of content assigned to this term.

    .Pages : All Pages assigned to this term. All list methods are available to this.


    WeightedPages is simply a slice of WeightedPage.

    type WeightedPages []WeightedPage

    .Count(term) : The number of pieces of content assigned to this term.

    .Pages : Returns a slice of pages, which then can be ordered using any of the list methods.

    Order Taxonomies

    Taxonomies can be ordered by either alphabetical key or by the number of content pieces assigned to that key.

    Order Alphabetically Example

      {{ $data := .Data }}
      {{ range $key, $value := .Data.Taxonomy.Alphabetical }}
      <li><a href="{{ $.Site.LanguagePrefix }}/{{ $data.Plural }}/{{ $value.Name | urlize }}"> {{ $value.Name }} </a> {{ $value.Count }} </li>
      {{ end }}

    Order by Popularity Example

      {{ $data := .Data }}
      {{ range $key, $value := .Data.Taxonomy.ByCount }}
      <li><a href="{{ $.Site.LanguagePrefix }}/{{ $data.Plural }}/{{ $value.Name | urlize }}"> {{ $value.Name }} </a> {{ $value.Count }} </li>
      {{ end }}

    Order Content within Taxonomies

    Hugo uses both date and weight to order content within taxonomies.

    Each piece of content in Hugo can optionally be assigned a date. It can also be assigned a weight for each taxonomy it is assigned to.

    When iterating over content within taxonomies, the default sort is the same as that used for section and list pages first by weight then by date. This means that if the weights for two pieces of content are the same, than the more recent content will be displayed first. The default weight for any piece of content is 0.

    Assign Weight

    Content can be assigned weight for each taxonomy that it's assigned to.

    tags = [ "a", "b", "c" ]
    tags_weight = 22
    categories = ["d"]
    title = "foo"
    categories_weight = 44
    Front Matter with weighted tags and categories

    The convention is taxonomyname_weight.

    In the above example, this piece of content has a weight of 22 which applies to the sorting when rendering the pages assigned to the "a", "b" and "c" values of the 'tag' taxonomy.

    It has also been assigned the weight of 44 when rendering the 'd' category.

    With this the same piece of content can appear in different positions in different taxonomies.

    Currently taxonomies only support the default ordering of content which is weight -> date.

    There are two different templates that the use of taxonomies will require you to provide.

    Both templates are covered in detail in the templates section.

    A list template is any template that will be used to render multiple pieces of content in a single html page. This template will be used to generate all the automatically created taxonomy pages.

    A taxonomy terms template is a template used to generate the list of terms for a given template.

    There are four common ways you can display the data in your taxonomies in addition to the automatic taxonomy pages created by hugo using the list templates:

    1. For a given piece of content, you can list the terms attached
    2. For a given piece of content, you can list other content with the same term
    3. You can list all terms for a taxonomy
    4. You can list all taxonomies (with their terms)

    Display a Single Piece of Content's Taxonomies

    Within your content templates, you may wish to display the taxonomies that piece of content is assigned to.

    Because we are leveraging the front matter system to define taxonomies for content, the taxonomies assigned to each content piece are located in the usual place (i.e., .Params.<TAXONOMYPLURAL>).

    Example: List Tags in a Single Page Template

    <ul id="tags">
      {{ range .Params.tags }}
        <li><a href="{{ "/tags/" | relLangURL }}{{ . | urlize }}">{{ . }}</a> </li>
      {{ end }}

    If you want to list taxonomies inline, you will have to take care of optional plural endings in the title (if multiple taxonomies), as well as commas. Let's say we have a taxonomy "directors" such as directors: [ "Joel Coen", "Ethan Coen" ] in the TOML-format front matter.

    To list such taxonomies, use the following:

    Example: Comma-delimit Tags in a Single Page Template

    {{ if .Params.directors }}
      <strong>Director{{ if gt (len .Params.directors) 1 }}s{{ end }}:</strong>
      {{ range $index, $director := .Params.directors }}{{ if gt $index 0 }}, {{ end }}<a href="{{ "directors/" | relURL }}{{ . | urlize }}">{{ . }}</a>{{ end }}
    {{ end }}

    Alternatively, you may use the delimit template function as a shortcut if the taxonomies should just be listed with a separator. See {{< gh 2143 >}} on GitHub for discussion.

    List Content with the Same Taxonomy Term

    If you are using a taxonomy for something like a series of posts, you can list individual pages associated with the same taxonomy. This is also a quick and dirty method for showing related content:

    Example: Showing Content in Same Series

      {{ range .Site.Taxonomies.series.golang }}
        <li><a href="{{ .Page.RelPermalink }}">{{ .Page.Title }}</a></li>
      {{ end }}

    List All content in a Given taxonomy

    This would be very useful in a sidebar as “featured content”. You could even have different sections of “featured content” by assigning different terms to the content.

    Example: Grouping "Featured" Content

    <section id="menu">
            {{ range $key, $taxonomy := .Site.Taxonomies.featured }}
            <li> {{ $key }} </li>
                {{ range $taxonomy.Pages }}
                <li hugo-nav="{{ .RelPermalink}}"><a href="{{ .Permalink}}"> {{ .LinkTitle }} </a> </li>
                {{ end }}
            {{ end }}

    Render a Site's Taxonomies

    If you wish to display the list of all keys for your site's taxonomy, you can retrieve them from the .Site variable available on every page.

    This may take the form of a tag cloud, a menu, or simply a list.

    The following example displays all terms in a site's tags taxonomy:

    Example: List All Site Tags

    <ul id="all-tags">
      {{ range $name, $taxonomy := .Site.Taxonomies.tags }}
        <li><a href="{{ "/tags/" | relLangURL }}{{ $name | urlize }}">{{ $name }}</a></li>
      {{ end }}

    Example: List All Taxonomies, Terms, and Assigned Content

    This example will list all taxonomies and their terms, as well as all the content assigned to each of the terms.

    {{< code file="layouts/partials/all-taxonomies.html" download="all-taxonomies.html" download="all-taxonomies.html" >}}

      {{ range $taxonomyname, $taxonomy := .Site.Taxonomies }}
    • {{ $taxonomyname }}
        {{ range $key, $value := $taxonomy }}
      • {{ $key }}
      • {{ end }}
    • {{ end }}
    {{< /code >}}

    .Site.GetPage for Taxonomies

    Because taxonomies are lists, the .GetPage function can be used to get all the pages associated with a particular taxonomy term using a terse syntax. The following ranges over the full list of tags on your site and links to each of the individual taxonomy pages for each term without having to use the more fragile URL construction of the "List All Site Tags" example above:

    {{< code file="links-to-all-tags" >}}

      {{ range ($.Site.GetPage "taxonomyTerm" "tags").Pages }}
    • {{ .Title}}
    • {{ end }}
    {{< /code >}}

    Single Page Templates

    Single Page Template Lookup Order

    You can specify a content's type and layout in a single content file's front matter. However, you cannot specify section because this is determined based on file location (see content section).

    Hugo assumes your content section and content type are the same unless you tell Hugo otherwise by providing a type directly in the front matter of a content file. This is why #1 and #3 come before #2 and #4, respectively, in the following lookup order. Values in angle brackets (<>) are variable.

    1. /layouts/<TYPE>/<LAYOUT>.html
    2. /layouts/<SECTION>>/<LAYOUT>.html
    3. /layouts/<TYPE>/single.html
    4. /layouts/<SECTION>/single.html
    5. /layouts/_default/single.html
    6. /themes/<THEME>/layouts/<TYPE>/<LAYOUT>.html
    7. /themes/<THEME>/layouts/<SECTION>/<LAYOUT>.html
    8. /themes/<THEME>/layouts/<TYPE>/single.html
    9. /themes/<THEME>/layouts/<SECTION>/single.html
    10. /themes/<THEME>/layouts/_default/single.html

    Example Single Page Templates

    Content pages are of the type page and will therefore have all the page variables and site variables available to use in their templates.


    This single page template makes use of Hugo base templates, the .Format function for dates, the .WordCount page variable, and ranges through the single content's specific taxonomies. [with][] is also used to check whether the taxonomies are set in the front matter.

    {{< code file="layouts/post/single.html" download="single.html" >}} {{ define "main" }}

    {{ .Title }}

    {{ .Content }}

    {{ .Date.Format "Mon Jan 2, 2006" }}

    {{ .WordCount }} Words
    {{ with .Params.topics }} {{ end }} {{ with .Params.tags }} {{ end }}
    {{ with .PrevInSection }} {{.Title}} {{ end }} {{ with .NextInSection }} {{.Title}} {{ end }}
    {{ end }} {{< /code >}}

    To easily generate new instances of a content type (e.g., new .md files in a section like project/) with preconfigured front matter, use content archetypes.

    [with]: /functions/with/

    Content View Templates

    These alternative content views are especially useful in list templates.

    The following are common use cases for content views:

    • You want content of every type to be shown on the homepage but only with limited summary views.
    • You only want a bulleted list of your content on a [taxonomy list page][taxonomylists]. Views make this very straightforward by delegating the rendering of each different type of content to the content itself.

    Create a Content View

    To create a new view, create a template in each of your different content type directories with the view name. The following example contains an "li" view and a "summary" view for the post and project content types. As you can see, these sit next to the single content view template, single.html. You can even provide a specific view for a given type and continue to use the_default/single.html` for the primary view.

      ▾ layouts/
        ▾ post/
        ▾ project/

    Hugo also has support for a default content template to be used in the event that a specific content view template has not been provided for that type. Content views can also be defined in the _default directory and will work the same as list and single templates who eventually trickle down to the _default directory as a matter of the lookup order.

    ▾ layouts/
      ▾ _default/

    Which Template Will be Rendered?

    The following is the lookup order for content views:

    1. /layouts/<TYPE>/<VIEW>.html
    2. /layouts/_default/<VIEW>.html
    3. /themes/<THEME>/layouts/<TYPE>/<VIEW>.html
    4. /themes/<THEME>/layouts/_default/<VIEW>.html

    Example: Content View Inside a List

    The following example demonstrates how to use content views inside of your list templates.


    In this example, .Render is passed into the template to call the render function. .Render is a special function that instructs content to render itself with the view template provided as the first argument. In this case, the template is going to render the summary.html view that follows:

    {{< code file="layouts/_default/list.html" download="list.html" >}}

    {{ .Title }}

    {{ range .Data.Pages }} {{ .Render "summary"}} {{ end }}
    {{< /code >}}


    Hugo will pass the entire page object to the following summary.html view template. (See Page Variables for a complete list.)

    {{< code file="layouts/_default/summary.html" download="summary.html" >}}

    {{ .Title }}

    {{ .Date.Format "Mon, Jan 2, 2006" }} - {{ .FuzzyWordCount }} Words
    {{ .Summary }} Read more → {{< /code >}}


    Continuing on the previous example, we can change our render function to use a smaller li.html view by changing the argument in the call to the .Render function (i.e., {{ .Render "li" }}).

    {{< code file="layouts/_default/li.html" download="li.html" >}}

  • {{ .Title }}
    {{ .Date.Format "Mon, Jan 2, 2006" }}
  • {{< /code >}}

    [taxonomylists]: /templates/taxonomy-templates/

    Data Templates

    Hugo supports loading data from YAML, JSON, and TOML files located in the data directory in the root of your Hugo project.

    The Data Folder

    The data folder is where you can store additional data for Hugo to use when generating your site. Data files aren't used to generate standalone pages; rather, they're meant to be supplemental to content files. This feature can extend the content in case your front matter fields grow out of control. Or perhaps you want to show a larger dataset in a template (see example below). In both cases, it's a good idea to outsource the data in their own files.

    These files must be YAML, JSON, or TOML files (using the .yml, .yaml, .json, or .toml extension). The data will be accessible as a map in the .Site.Data variable.

    Data Files in Themes

    Data Files can also be used in Hugo themes but note that theme data files follow the same logic as other template files in the Hugo lookup order (i.e., given two files with the same name and relative path, the file in the root project data directory will override the file in the themes/<THEME>/data directory).

    Therefore, theme authors should take care to not include data files that could be easily overwritten by a user who decides to customize a theme. For theme-specific data items that shouldn't be overridden, it can be wise to prefix the folder structure with a namespace; e.g. mytheme/data/<THEME>/somekey/.... To check if any such duplicate exists, run hugo with the -v flag.

    The keys in the map created with data templates from data files will be a dot-chained set of path, filename, and key in file (if applicable).

    This is best explained with an example:

    Example: Jaco Pastorius' Solo Discography

    Jaco Pastorius was a great bass player, but his solo discography is short enough to use as an example. John Patitucci is another bass giant.

    The example below is a bit contrived, but it illustrates the flexibility of data Files. This example uses TOML as its file format with the two following data files:

    • data/jazz/bass/jacopastorius.toml
    • data/jazz/bass/johnpatitucci.toml

    jacopastorius.toml contains the content below. johnpatitucci.toml contains a similar list:

    discography = [
    "1974 – Modern American Music … Period! The Criteria Sessions",
    "1974 – Jaco",
    "1976 - Jaco Pastorius",
    "1981 - Word of Mouth",
    "1981 - The Birthday Concert (released in 1995)",
    "1982 - Twins I & II (released in 1999)",
    "1983 - Invitation",
    "1986 - Broadway Blues (released in 1998)",
    "1986 - Honestly Solo Live (released in 1990)",
    "1986 - Live In Italy (released in 1991)",
    "1986 - Heavy'n Jazz (released in 1992)",
    "1991 - Live In New York City, Volumes 1-7.",
    "1999 - Rare Collection (compilation)",
    "2003 - Punk Jazz: The Jaco Pastorius Anthology (compilation)",
    "2007 - The Essential Jaco Pastorius (compilation)"

    The list of bass players can be accessed via .Site.Data.jazz.bass, a single bass player by adding the filename without the suffix, e.g. .Site.Data.jazz.bass.jacopastorius.

    You can now render the list of recordings for all the bass players in a template:

    {{ range $.Site.Data.jazz.bass }}
       {{ partial "artist.html" . }}
    {{ end }}

    And then in the partial/artist.html:

    {{ range .discography }}
      <li>{{ . }}</li>
    {{ end }}

    Discover a new favorite bass player? Just add another .toml file in the same directory.

    Example: Accessing Named Values in a Data File

    Assume you have the following YAML structure in your User0123.yml data file located directly in data/:

    Name: User0123
    "Short Description": "He is a **jolly good** fellow."
      - "Can create a Key, Value list from Data File"
      - "Learns Hugo"
      - "Reads documentation"

    You can use the following code to render the Short Description in your layout::

    <div>Short Description of {{.Site.Data.User0123.Name}}: <p>{{ index .Site.Data.User0123 "Short Description" | markdownify }}</p></div>

    Note the use of the markdownify template function. This will send the description through the Blackfriday Markdown rendering engine.

    Data-Driven Content

    In addition to the data files feature, Hugo also a "data-driven content" feature, which lets you load any JSON or CSV file from nearly any resource.

    Data-driven content currently consists of two functions, getJSON and getCSV, which are available in all template files.

    Implementation details

    Call the Functions with a URL

    In your template, call the functions like this:

    {{ $dataJ := getJSON "url" }}
    {{ $dataC := getCSV "separator" "url" }}

    If you use a prefix or postfix for the URL, the functions accept variadic arguments:

    {{ $dataJ := getJSON "url prefix" "arg1" "arg2" "arg n" }}
    {{ $dataC := getCSV  "separator" "url prefix" "arg1" "arg2" "arg n" }}

    The separator for getCSV must be put in the first position and can only be one character long.

    All passed arguments will be joined to the final URL:

    {{ $urlPre := "" }}
    {{ $gistJ := getJSON $urlPre "/users/GITHUB_USERNAME/gists" }}

    This will resolve internally to the following:

    {{ $gistJ := getJSON "" }}

    Finally, you can range over an array. This example will output the first 5 gists for a GitHub user:

      {{ $urlPre := "" }}
      {{ $gistJ := getJSON $urlPre "/users/GITHUB_USERNAME/gists" }}
      {{ range first 5 $gistJ }}
        {{ if .public }}
          <li><a href="{{ .html_url }}" target="_blank">{{ .description }}</a></li>
        {{ end }}
      {{ end }}

    Example for CSV files

    For getCSV, the one-character-long separator must be placed in the first position followed by the URL. The following is an example of creating an HTML table in a partial template from a published CSV:

    {{< code file="layouts/partials/get-csv.html" >}}

    {{ $url := "" }} {{ $sep := "," }} {{ range $i, $r := getCSV $sep $url }} {{ end }}
    Name Position Salary
    {{ index $r 0 }} {{ index $r 1 }} {{ index $r 2 }}
    {{< /code >}}

    The expression {{index $r number}} must be used to output the nth-column from the current row.

    Cache URLs

    Each downloaded URL will be cached in the default folder $TMPDIR/hugo_cache/. The variable $TMPDIR will be resolved to your system-dependent temporary directory.

    With the command-line flag --cacheDir, you can specify any folder on your system as a caching directory.

    You can also set cacheDir in the main configuration file.

    If you don't like caching at all, you can fully disable caching with the command line flag --ignoreCache.

    Authentication When Using REST URLs

    Currently, you can only use those authentication methods that can be put into an URL. OAuth and other authentication methods are not implemented.

    Load Local files

    To load local files with getJSON and getCSV, the source files must reside within Hugo's working directory. The file extension does not matter, but the content does.

    It applies the same output logic as above in Calling the Functions with a URL.

    LiveReload with Data Files

    There is no chance to trigger a LiveReload when the content of a URL changes. However, when a local file changes (i.e., data/* and themes/<THEME>/data/*), a LiveReload will be triggered. Symlinks are not supported. Note too that because downloading of data takes a while, Hugo stops processing your Markdown files until the data download has completed.

    {{% warning "URL Data and LiveReload" %}} If you change any local file and the LiveReload is triggered, Hugo will read the data-driven (URL) content from the cache. If you have disabled the cache (i.e., by running the server with hugo server --ignoreCache), Hugo will re-download the content every time LiveReload triggers. This can create huge traffic. You may reach API limits quickly. {{% /warning %}}

    Examples of Data-driven Content

    Specs for Data Formats

    Partial Templates

    Partial Template Lookup Order

    Partial templates---like single page templates and list page templates---have a specific lookup order. However, partials are simpler in that Hugo will only check in two places:

    1. layouts/partials/*<PARTIALNAME>.html
    2. themes/<THEME>/layouts/partials/*<PARTIALNAME>.html

    This allows a theme's end user to copy a partial's contents into a file of the same name for further customization.

    Use Partials in your Templates

    All partials for your Hugo project are located in a single layouts/partials directory. For better organization, you can create multiple subdirectories within partials as well:

    └── layouts
        └── partials
            ├── footer
            │   ├── scripts.html
            │   └── site-footer.html
            ├── head
            │   ├── favicons.html
            │   ├── metadata.html
            │   ├── prerender.html
            │   └── twitter.html
            └── header
                ├── site-header.html
                └── site-nav.html

    All partials are called within your templates using the following pattern:

    {{ partial "<PATH>/<PARTIAL>.html" . }}

    {{% note %}} One of the most common mistakes with new Hugo users is failing to pass a context to the partial call. In the pattern above, note how "the dot" (.) is required as the second argument to give the partial context. You can read more about "the dot" in the Hugo templating introduction. {{% /note %}}

    As shown in the above example directory structure, you can nest your directories within partials for better source organization. You only need to call the nested partial's path relative to the partials directory:

    {{ partial "header/site-header.html" . }}
    {{ partial "footer/scripts.html" . }}

    {{% note %}} Before v0.12, Hugo used the template call to include partial templates. When using Hugo v0.12 and newer, be sure to use the {{ partial "<PATH>/<PARTIAL>.html" . }} syntax. The old approach will still work but has fewer benefits. {{% /note %}}

    Variable Scoping

    The second argument in a partial call is the variable being passed down. The above examples are passing the ., which tells the template receiving the partial to apply the current context.

    This means the partial will only be able to access those variables. The partial is isolated and has no access to the outer scope. From within the partial, $.Var is equivalent to .Var.

    Cached Partials

    The partialCached template function can offer significant performance gains for complex templates that don't need to be re-rendered on every invocation. The simplest usage is as follows:

    {{ partialCached "footer.html" . }}

    You can also pass additional parameters to partialCached to create variants of the cached partial.

    For example, you can tell Hugo to only render the partial footer.html once per section:

    {{ partialCached "footer.html" . .Section }}

    If you need to pass additional parameters to create unique variants, you can pass as many variant parameters as you need:

    {{ partialCached "footer.html" . .Params.province }}

    Note that the variant parameters are not made available to the underlying partial template. They are only use to create a unique cache key.

    Example header.html

    The following header.html partial template is used for

    {{< code file="layouts/partials/header.html" download="header.html" >}}

    {{ partial "meta.html" . }}
    <base href="{{ .Site.BaseURL }}">
    <title> {{ .Title }} : </title>
    <link rel="canonical" href="{{ .Permalink }}">
    {{ if .RSSLink }}<link href="{{ .RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Title }}" />{{ end }}
    {{ partial "head_includes.html" . }}
    {{< /code >}}

    {{% note %}} The header.html example partial was built before the introduction of block templates to Hugo. Read more on base templates and blocks for defining the outer chrome or shell of your master templates (i.e., your site's head, header, and footer). You can even combine blocks and partials for added flexibility. {{% /note %}}

    Example footer.html

    The following footer.html partial template is used for

    {{< code file="layouts/partials/footer.html" download="footer.html" >}}

    © 2013-14 Steve Francia. Some rights reserved; please attribute properly and link back. Hosted by ServerGrove.

    <script type="text/javascript">

    var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-XYSYXYSY-X']); _gaq.push(['_trackPageview']);

    (function() { var ga = document.createElement('script'); ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + ''; ga.setAttribute('async', 'true'); document.documentElement.firstChild.appendChild(ga); })();

    </script> {{< /code >}}

    themes: /themes/

    Create Your Own Shortcodes

    Shortcodes are a means to consolidate templating into small, reusable snippets that you can embed directly inside of your content. In this sense, you can think of shortcodes as the intermediary between page and list templates and basic content files.

    {{% note %}} Hugo also ships with built-in shortcodes for common use cases. (See Content Management: Shortcodes.) {{% /note %}}

    Create Custom Shortcodes

    Hugo's built-in shortcodes cover many common, but not all, use cases. Luckily, Hugo provides the ability to easily create custom shortcodes to meet your website's needs.

    File Placement

    To create a shortcode, place an HTML template in the layouts/shortcodes directory of your source organization. Consider the file name carefully since the shortcode name will mirror that of the file but without the .html extension. For example, layouts/shortcodes/myshortcode.html will be called with either {{</* myshortcode /*/>}} or {{%/* myshortcode /*/%}} depending on the type of parameters you choose.

    Shortcode Template Lookup Order

    Shortcode templates have a simple lookup order:

    1. /layouts/shortcodes/<SHORTCODE>.html
    2. /themes/<THEME>/layouts/shortcodes/<SHORTCODE>.html

    Positional vs Named Parameters

    You can create shortcodes using the following types of parameters:

    • Positional parameters
    • Named parameters
    • Positional or named parameters (i.e, "flexible")

    In shortcodes with positional parameters, the order of the parameters is important. If a shortcode has a single required value (e.g., the youtube shortcode below), positional parameters work very well and require less typing from content authors.

    For more complex layouts with multiple or optional parameters, named parameters work best. While less terse, named parameters require less memorization from a content author and can be added in a shortcode declaration in any order.

    Allowing both types of parameters (i.e., a "flexible" shortcode) is useful for complex layouts where you want to set default values that can be easily overridden by users.

    Access Parameters

    All shortcode parameters can be accessed via the .Get method. Whether you pass a key (i.e., string) or a number to the .Get method depends on whether you are accessing a named or positional parameter, respectively.

    To access a parameter by name, use the .Get method followed by the named parameter as a quoted string:

    {{ .Get "class" }}

    To access a parameter by position, use the .Get followed by a numeric position, keeping in mind that positional parameters are zero-indexed:

    {{ .Get 0 }}

    with is great when the output depends on a parameter being set:

    {{ with .Get "class"}} class="{{.}}"{{ end }}

    .Get can also be used to check if a parameter has been provided. This is most helpful when the condition depends on either of the values, or both:

    {{ or .Get "title" | .Get "alt" | if }} alt="{{ with .Get "alt"}}{{.}}{{else}}{{.Get "title"}}{{end}}"{{ end }}


    If a closing shortcode is used, the .Inner variable will be populated with all of the content between the opening and closing shortcodes. If a closing shortcode is required, you can check the length of .Inner as an indicator of its existence.

    A shortcode with content declared via the .Inner variable can also be declared without the inline content and without the closing shortcode by using the self-closing syntax:

    {{</* innershortcode /*/>}}


    The .Params variable in shortcodes contains the list parameters passed to shortcode for more complicated use cases. You can also access higher-scoped parameters with the following logic:

    $.Params : these are the parameters passed directly into the shortcode declaration (e.g., a YouTube video ID)

    $.Page.Params : refers to the page's params; the "page" in this case refers to the content file in which the shortcode is declared (e.g., a shortcode_color field in a content's front matter could be accessed via $.Page.Params.shortcode_color).

    $.Page.Site.Params : refers to global variables as defined in your site's configuration file.


    The .IsNamedParams variable checks whether the shortcode declaration uses named parameters and returns a boolean value.

    For example, you could create an image shortcode that can take either a src named parameter or the first positional parameter, depending on the preference of the content's author. Let's assume the image shortcode is called as follows:

    {{</* image src="images/my-image.jpg"*/>}}

    You could then include the following as part of your shortcode templating:

    {{ if .IsNamedParams }}
    <img src="{{.Get "src" alt="">
    {{ else }}
    <img src="{{.Get 0}}" alt="">
    {{ end }}.

    See the example Vimeo shortcode below for .IsNamedParams in action.

    {{% warning %}} While you can create shortcode templates that accept both positional and named parameters, you cannot declare shortcodes in content with a mix of parameter types. Therefore, a shortcode declared like {{</* image src="images/my-image.jpg" "This is my alt text" */>}} will return an error. {{% /warning %}}

    You can also use the variable .Page to access all the normal page variables.

    A shortcodes can also be nested. In a nested shortcode, you can access the parent shortcode context with .Parent variable. This can be very useful for inheritance of common shortcode parameters from the root.

    Custom Shortcode Examples

    The following are examples of the different types of shortcodes you can create via shortcode template files in /layouts/shortcodes.

    Single-word Example: year

    Let's assume you would like to keep mentions of your copyright year current in your content files without having to continually review your markdown. Your goal is to be able to call the shortcode as follows:

    {{</* year */>}}

    {{< code file="/layouts/shortcodes/year.html" >}} {{ .Page.Now.Year }} {{< /code >}}

    Single Positional Example: youtube

    Embedded videos are a common addition to markdown content that can quickly become unsightly. The following is the code used by [Hugo's built-in YouTube shortcode][youtubeshortcode]:

    {{</* youtube 09jf3ow9jfw */>}}

    Would load the template at /layouts/shortcodes/youtube.html:

    {{< code file="/layouts/shortcodes/youtube.html" >}}

    <iframe class="youtube-player" type="text/html" width="640" height="385" src="{{ index .Params 0 }}" allowfullscreen frameborder="0"> </iframe>
    {{< /code >}}

    {{< code file="youtube-embed.html" copy="false" >}}

    <iframe class="youtube-player" type="text/html" width="640" height="385" src="" allowfullscreen frameborder="0"> </iframe>
    {{< /code >}}

    Single Named Example: image

    Let's say you want to create your own img shortcode rather than use Hugo's built-in figure shortcode. Your goal is to be able to call the shortcode as follows in your content files:

    {{< code file="" >}} {{</* img src="/media/spf13.jpg" title="Steve Francia" */>}} {{< /code >}}

    You have created the shortcode at /layouts/shortcodes/img.html, which loads the following shortcode template:

    {{< code file="/layouts/shortcodes/img.html" >}}

    {{ with .Get "link"}}{{ end }} {{ if .Get "link"}}{{ end }} {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}} {{ if isset .Params "title" }}

    {{ .Get "title" }}

    {{ end }} {{ if or (.Get "caption") (.Get "attr")}}

    {{ .Get "caption" }} {{ with .Get "attrlink"}} {{ end }} {{ .Get "attr" }} {{ if .Get "attrlink"}} {{ end }}

    {{ end }} {{ end }} {{< /code >}}

    Would be rendered as:

    {{< code file="img-output.html" copy="false" >}}

    Steve Francia

    {{< /code >}}

    Single Flexible Example: vimeo

    {{</* vimeo 49718712 */>}}
    {{</* vimeo id="49718712" class="flex-video" */>}}

    Would load the template found at /layouts/shortcodes/vimeo.html:

    {{< code file="/layouts/shortcodes/vimeo.html" >}} {{ if .IsNamedParams }}

    <iframe src="//{{ .Get "id" }}" allowfullscreen></iframe>
    {{ else }}
    <iframe src="//{{ .Get 0 }}" allowfullscreen></iframe>
    {{ end }} {{< /code >}}

    Would be rendered as:

    {{< code file="vimeo-iframes.html" copy="false" >}}

    <iframe src="//" allowfullscreen></iframe>
    <iframe src="//" allowfullscreen></iframe>
    {{< /code >}}

    Paired Example: highlight

    The following is taken from highlight, which is a built-in shortcode that ships with Hugo.

    {{< code file="" >}} {{</* highlight html */>}}

    This HTML {{}} {{< /code >}}

    The template for the highlight shortcode uses the following code, which is already included in Hugo:

    {{ .Get 0 | highlight .Inner  }}

    The rendered output of the HTML example code block will be as follows:

    {{< code file="syntax-highlighted.html" copy="false" >}}

        <body> This HTML </body>
    {{< /code >}}

    {{% note %}} The preceding shortcode makes use of a Hugo-specific template function called highlight, which uses Pygments to add syntax highlighting to the example HTML code block. See the developer tools page on syntax highlighting for more information. {{% /note %}}

    Nested Shortcode: Image Gallery

    Hugo's .Parent shortcode variable returns a boolean value depending on whether the shortcode in question is called within the context of a parent shortcode. This provides an inheritance model for common shortcode parameters.

    The following example is contrived but demonstrates the concept. Assume you have a gallery shortcode that expects one named class parameter:

    {{< code file="layouts/shortcodes/gallery.html" >}}

    {{< /code >}}

    You also have an image shortcode with a single named src parameter that you want to call inside of gallery and other shortcodes so that the parent defines the context of each image:

    {{< code file="layouts/shortcodes/image.html" >}} {{- $src := .Get "src" -}} {{- with .Parent -}} <img src="{{$src}}" class="{{.Get "class"}}-image"> {{- else -}} {{- end }} {{< /code >}}

    You can then call your shortcode in your content as follows:

    {{</* gallery class="content-gallery" */>}}
      {{</* img src="/images/one.jpg" */>}}
      {{</* img src="/images/two.jpg" */>}}
    {{</* /gallery */>}}
    {{</* img src="/images/three.jpg" */>}}

    This will output the following HTML. Note how the first two image shortcodes inherit the class value of content-gallery set with the call to the parent gallery, whereas the third image only uses src:

    <div class="content-gallery">
        <img src="/images/one.jpg" class="content-gallery-image">
        <img src="/images/two.jpg" class="content-gallery-image">
    <img src="/images/three.jpg">

    More Shortcode Examples

    More shortcode examples can be found in the shortcodes directory for and the shortcodes directory for the Hugo docs.

    [youtubeshortcode]: /content-management/shortcodes/#youtube "See how to use Hugo's built-in YouTube shortcode."

    Local File Templates

    Traverse Local Files

    With Hugo's readDir and readFile template functions, you can traverse your website's files on your server.

    Use readDir

    The readDir function returns an array of os.FileInfo. It takes the file's path as a single string argument. This path can be to any directory of your website (i.e., as found on your server's file system).

    Whether the path is absolute or relative does not matter because---at least for readDir---the root of your website (typically ./public/) in effect becomes both:

    1. The file system root
    2. The current working directory

    readDir Example: List Directory Files

    This shortcode creates a link to each of the files in a directory---display as the file's basename---along with the file's size in bytes.

    {{< code file="layouts/shortcodes/directoryindex.html" download="directoryindex.html" >}} {{< readfile file="/themes/gohugoioTheme/layouts/shortcodes/directoryindex.html" >}} {{< /code >}}

    You can then call the shortcode as follows inside of your content's markup:

    {{</* directoryindex path="/static/css" pathURL="/css" */>}}

    The above shortcode is part of the code for the Hugo docs. Here it lists this site's CSS files:

    {{< directoryindex path="/themes/gohugoioTheme/static/dist" pathURL="/css" >}}

    {{% note "Slashes are Important" %}} The initial slash / in pathURL is important in the directoryindex shortcode. Otherwise, pathURL becomes relative to the current web page. {{% /note %}}

    Use readFile

    The readfile function reads a file from disk and converts it into a string to be manipulated by other Hugo functions or added as-is. readFile takes the file, including path, as an argument passed to the function.

    To use the readFile function in your templates, make sure the path is relative to your Hugo project's root directory:

    {{ readFile "/content/templates/local-file-templates" }}

    readFile Example: Add a Project File to Content

    As readFile is a function, it is only available to you in your templates and not your content. However, we can create a simple shortcode template that calls readFile, passes the first argument through the function, and then allows an optional second argument to send the file through the Blackfriday markdown processor. The pattern for adding this shortcode to your content will be as follows:

    {{</* readfile file="/path/to/local/file.txt" markdown="true" */>}}

    {{% warning %}} If you are going to create custom shortcodes with readFile for a theme, note that usage of the shortcode will refer to the project root and not your themes directory. {{% /warning %}}

    Here is the templating for our new readfile shortcode:

    {{< code file="layouts/shortcodes/readfile.html" download="readfile.html" >}} {{< readfile file="/themes/gohugoioTheme/layouts/shortcodes/readfile.html">}} {{< /code >}}

    This readfile shortcode is also part of the Hugo docs. So is testing.txt, which we will call in this example by passing it into our new readfile shortcode as follows:

    {{</* readfile file="/content/readfiles/testing.txt" */>}}

    The output "string" for this shortcode declaration will be the following:

    {{< readfile file="/content/readfiles/testing.txt" >}}

    However, if we want Hugo to pass this string through Blackfriday, we should add the markdown="true" optional parameter:

    {{</* readfile file="/content/readfiles/testing.txt" markdown="true" */>}}

    And here is the result as called directly in the Hugo docs and rendered for display:

    {{< readfile file="/content/readfiles/testing.txt" markdown="true">}}

    Custom 404 Page

    When using Hugo with GitHub Pages, you can provide your own template for a custom 404 error page by creating a 404.html template file in your /layouts folder. When Hugo generates your site, the 404.html file will be placed in the root.

    404 pages will have all the regular page variables available to use in the templates.

    In addition to the standard page variables, the 404 page has access to all site content accessible from .Data.Pages.

    ▾ layouts/


    This is a basic example of a 404.html template:

    {{< code file="layouts/404.html" download="404.html" >}} {{ define "main"}}

    <a href="{{ "/" | relURL }}">Go Home

    {{ end }} {{< /code >}}

    Automatic Loading

    Your 404.html file can be set to load automatically when a visitor enters a mistaken URL path, dependent upon the web serving environment you are using. For example:

    • GitHub Pages. The 404 page is automatic.
    • Apache. You can specify ErrorDocument 404 /404.html in an .htaccess file in the root of your site.
    • Nginx. You might specify error_page 404 /404.html; in your nginx.conf file.
    • Amazon AWS S3. When setting a bucket up for static web serving, you can specify the error file from within the S3 GUI.
    • Caddy Server. Using errors { 404 /404.html }. Details here

    pagevars: /variables/page/

    Menu Templates

    Hugo makes no assumptions about how your rendered HTML will be structured. Instead, it provides all of the functions you will need to be able to build your menu however you want.

    The following is an example:

    {{< code file="layouts/partials/sidebar.html" download="sidebar.html" >}}

      {{ $currentPage := . }} {{ range .Site.Menus.main }} {{ if .HasChildren }}
              <li class="sub-menu{{if $currentPage.HasMenuCurrent "main" . }} active{{end}}">
              <a href="javascript:;" class="">
                  {{ .Pre }}
                  <span>{{ .Name }}</span>
                  <span class="menu-arrow arrow_carrot-right"></span>
              <ul class="sub">
                  {{ range .Children }}
                  <li{{if $currentPage.IsMenuCurrent "main" . }} class="active"{{end}}><a href="{{.URL}}"> {{ .Name }} </a> </li>
                  {{ end }}
              <a href="{{.URL}}">
                  {{ .Pre }}
                  <span>{{ .Name }}</span>
              <li> <a href="" target="blank">Questions and Issues</a> </li>
              <li> <a href="#" target="blank">Edit this Page</a> </li>
          <!-- sidebar menu end-->
    {{< /code >}}

    {{% note "absLangURL and relLangURL" %}} Use the absLangUrl or relLangUrl functions if your theme makes use of the multilingual feature. In contrast to absURL and relURL, these two functions add the correct language prefix to the url. {{% /note %}}

    Section Menu for Lazy Bloggers

    To enable this menu, configure sectionPagesMenu in your site config:

    sectionPagesMenu = "main"

    The menu name can be anything, but take a note of what it is.

    This will create a menu with all the sections as menu items and all the sections' pages as "shadow-members". The shadow implies that the pages isn't represented by a menu-item themselves, but this enables you to create a top-level menu like this:

    <nav class="sidebar-nav">
        {{ $currentPage := . }}
        {{ range .Site.Menus.main }}
        <a class="sidebar-nav-item{{if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} active{{end}}" href="{{.URL}}">{{ .Name }}</a>
        {{ end }}

    In the above, the menu item is marked as active if on the current section's list page or on a page in that section.

    The above is all that's needed. But if you want custom menu items, e.g. changing weight or name, you can define them manually in the site config, i.e. config.toml:

        name = "This is the blog section"
        weight = -110
        identifier = "blog"
        url = "/blog/"

    {{% note %}} The identifier must match the section name. {{% /note %}}


    The real power of Hugo pagination shines when combined with the where function and its SQL-like operators: first, last, and after. You can even order the content the way you've become used to with Hugo.

    Configure Pagination

    Pagination can be configured in your site configuration:

    Paginate : default = 10. This setting can be overridden within the template.

    PaginatePath : default = page. Allows you to set a different path for your pagination pages.

    Setting Paginate to a positive value will split the list pages for the homepage, sections and taxonomies into chunks of that size. But note that the generation of the pagination pages for sections, taxonomies and homepage is lazy --- the pages will not be created if not referenced by a .Paginator (see below).

    PaginatePath is used to adapt the URL to the pages in the paginator (the default setting will produce URLs on the form /page/1/.

    List Paginator Pages

    {{% warning %}} .Paginator is provided to help you build a pager menu. This feature is currently only supported on homepage and list pages (i.e., taxonomies and section lists). {{% /warning %}}

    There are two ways to configure and use a .Paginator:

    1. The simplest way is just to call .Paginator.Pages from a template. It will contain the pages for that page.
    2. Select a subset of the pages with the available template functions and ordering options, and pass the slice to .Paginate, e.g. {{ range (.Paginate ( first 50 .Data.Pages.ByTitle )).Pages }}.

    For a given Page, it's one of the options above. The .Paginator is static and cannot change once created.

    The global page size setting (Paginate) can be overridden by providing a positive integer as the last argument. The examples below will give five items per page:

    • {{ range (.Paginator 5).Pages }}
    • {{ $paginator := .Paginate (where .Data.Pages "Type" "post") 5 }}

    It is also possible to use the GroupBy functions in combination with pagination:

    {{ range (.Paginate (.Data.Pages.GroupByDate "2006")).PageGroups  }}

    Build the navigation

    The .Paginator contains enough information to build a paginator interface.

    The easiest way to add this to your pages is to include the built-in template (with Bootstrap-compatible styles):

    {{ template "_internal/pagination.html" . }}

    {{% note "When to Create .Paginator" %}} If you use any filters or ordering functions to create your .Paginator and you want the navigation buttons to be shown before the page listing, you must create the .Paginator before it's used. {{% /note %}}

    The following example shows how to create .Paginator before its used:

    {{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}
    {{ template "_internal/pagination.html" . }}
    {{ range $paginator.Pages }}
       {{ .Title }}
    {{ end }}

    Without the where filter, the above example is even simpler:

    {{ template "_internal/pagination.html" . }}
    {{ range .Paginator.Pages }}
       {{ .Title }}
    {{ end }}

    If you want to build custom navigation, you can do so using the .Paginator object, which includes the following properties:

    PageNumber : The current page's number in the pager sequence

    URL: The relative URL to the current pager

    Pages: The pages in the current pager

    NumberOfElements : The number of elements on this page

    HasPrev : Whether there are page(s) before the current

    Prev : The pager for the previous page

    HasNext : Whether there are page(s) after the current

    Next : The pager for the next page

    First : The pager for the first page

    Last : The pager for the last page

    Pagers : A list of pagers that can be used to build a pagination menu

    PageSize : Size of each pager

    TotalPages : The number of pages in the paginator

    TotalNumberOfElements : The number of elements on all pages in this paginator

    Additional information

    The pages are built on the following form (BLANK means no value):

    [SECTION/TAXONOMY/BLANK]/page/1/index.html => redirect to  [SECTION/TAXONOMY/BLANK]/index.html

    where: /functions/where/

    RSS Templates

    RSS Template Lookup Order

    You can use a single RSS template to generate all of your RSS feeds or create a specific template for each individual feed.

    1. /layouts/section/<section>.rss.xml
    2. /layouts/_default/rss.xml
    3. /themes/<theme>/layouts/section/<section>.rss.xml
    4. /themes/<theme>/layouts/_default/rss.xml

    {{% note "Hugo Ships with an RSS Template" %}} Hugo ships with its own RSS 2.0 template. The embedded template will be sufficient for most use cases. {{% /note %}}

    RSS pages are of the type Page and have all the page variables available to use in the templates.

    Section RSS

    A section’s RSS will be rendered at /<SECTION>/index.xml (e.g.,

    Hugo provides the ability for you to define any RSS type you wish and can have different RSS files for each section and taxonomy.

    Lookup Order for RSS Templates

    Main RSS

    1. /layouts/rss.xml
    2. /layouts/_default/rss.xml
    3. Embedded rss.xml

    Section RSS

    1. /layouts/section/<SECTION>.rss.xml
    2. /layouts/_default/rss.xml
    3. /themes/<THEME>/layouts/section/<SECTION>.rss.xml
    4. /themes/<THEME>/layouts/_default/rss.xml
    5. Embedded rss.xml

    Taxonomy RSS

    1. /layouts/taxonomy/<SINGULAR>.rss.xml
    2. /layouts/_default/rss.xml
    3. /themes/<THEME>/layouts/taxonomy/<SINGULAR>.rss.xml
    4. /themes/<THEME>/layouts/_default/rss.xml
    5. Embedded rss.xml

    Configure RSS

    By default, Hugo will create an unlimited number of RSS entries. You can limit the number of articles included in the built-in RSS templates by assigning a numeric value to rssLimit: field in your project's config file.

    The following values will also be included in the RSS output if specified in your site’s configuration:

    languageCode = "en-us"
    copyright = "This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License."
        name = "My Name Here"

    The Embedded rss.xml

    This is the default RSS template that ships with Hugo. It adheres to the RSS 2.0 Specification.

    <rss version="2.0" xmlns:atom="">
        <title>{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}</title>
        <link>{{ .Permalink }}</link>
        <description>Recent content {{ with .Title }}in {{.}} {{ end }}on {{ .Site.Title }}</description>
        <generator>Hugo --</generator>{{ with .Site.LanguageCode }}
        <language>{{.}}</language>{{end}}{{ with }}
        <managingEditor>{{.}}{{ with $ }} ({{.}}){{end}}</managingEditor>{{end}}{{ with }}
        <webMaster>{{.}}{{ with $ }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
        <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
        <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
        <atom:link href="{{.URL}}" rel="self" type="application/rss+xml" />
        {{ range first 15 .Data.Pages }}
          <title>{{ .Title }}</title>
          <link>{{ .Permalink }}</link>
          <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
          {{ with }}<author>{{.}}{{ with $ }} ({{.}}){{end}}</author>{{end}}
          <guid>{{ .Permalink }}</guid>
          <description>{{ .Content | html }}</description>
        {{ end }}

    {{% warning "XML Header" %}} Hugo will automatically add the following header line to this file on render. Please do not include this in the template as it's not valid HTML.

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?>

    {{% /warning %}}

    Reference your RSS Feed in <head>

    In your header.html template, you can specify your RSS feed in your <head></head> tag like this:

    {{ if .RSSLink }}
      <link href="{{ .RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}" />
      <link href="{{ .RSSLink }}" rel="feed" type="application/rss+xml" title="{{ .Site.Title }}" />
    {{ end }}

    ...with the auto-discovery link specified by the line with rel="alternate".

    The .RSSLink will render the appropriate RSS feed URL for the section, whether it's everything, posts in a section, or a taxonomy.

    If you reference your RSS link, be sure to specify the MIME type with type="application/rss+xml".

    <a href="{{ .URL }}" type="application/rss+xml" target="_blank">{{ .SomeText }}</a>

    Sitemap Template

    A single Sitemap template is used to generate the sitemap.xml file. Hugo automatically comes with this template file. No work is needed on the users' part unless they want to customize sitemap.xml.

    A sitemap is a Page and therefore has all the page variables available to use in this template along with Sitemap-specific ones:

    .Sitemap.ChangeFreq : The page change frequency

    .Sitemap.Priority : The priority of the page

    .Sitemap.Filename : The sitemap filename

    If provided, Hugo will use /layouts/sitemap.xml instead of the internal sitemap.xml template that ships with Hugo.

    Hugo’s sitemap.xml

    This template respects the version 0.9 of the Sitemap Protocol.

    <urlset xmlns="">
      {{ range .Data.Pages }}
        <loc>{{ .Permalink }}</loc>{{ if not .Lastmod.IsZero }}
        <lastmod>{{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}</lastmod>{{ end }}{{ with .Sitemap.ChangeFreq }}
        <changefreq>{{ . }}</changefreq>{{ end }}{{ if ge .Sitemap.Priority 0.0 }}
        <priority>{{ .Sitemap.Priority }}</priority>{{ end }}
      {{ end }}

    {{% note %}} Hugo will automatically add the following header line to this file on render. Please don't include this in the template as it's not valid HTML.

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?> {{% /note %}}

    Configure sitemap.xml

    Defaults for <changefreq>, <priority> and filename values can be set in the site's config file, e.g.:

      changefreq = "monthly"
      priority = 0.5
      filename = "sitemap.xml"

    The same fields can be specified in an individual content file's front matter in order to override the value assigned to that piece of content at render time.

    pagevars: /variables/page/

    Robots.txt File

    To create your robots.txt as a template, first set the enableRobotsTXT value to true in your configuration file. By default, this option generates a robots.txt with the following content, which tells search engines that they are allowed to crawl everything:

    User-agent: *

    Robots.txt Template Lookup Order

    The lookup order for the robots.txt template is as follows:

    • /layouts/robots.txt
    • /themes/<THEME>/layout/robots.txt

    {{% note %}} If you do not want Hugo to create a default robots.txt or leverage the robots.txt template, you can hand code your own and place the file in static. Remember that everything in the static directory is copied over as-is when Hugo builds your site. {{% /note %}}

    Robots.txt Template Example

    The following is an example robots.txt layout:

    {{< code file="layouts/robots.txt" download="robots.txt" >}} User-agent: *

    {{range .Data.Pages}} Disallow: {{.RelPermalink}} {{end}} {{< /code >}}

    This template disallows all the pages of the site by creating one Disallow entry for each page.


    Internal Templates

    {{% warning %}} While the following internal templates are called similar to partials, they do not observe the partial template lookup order. {{% /warning %}}

    Google Analytics

    Hugo ships with internal templates for Google Analytics tracking, including both synchronous and asynchronous tracking codes.

    Configure Google Analytics

    Provide your tracking id in your configuration file:

    googleAnalytics = "UA-123-45"
    googleAnalytics: "UA-123-45"

    Use the Google Analytics Template

    You can then include the Google Analytics internal template:

    {{ template "_internal/google_analytics.html" . }}
    {{ template "_internal/google_analytics_async.html" . }}


    Hugo also ships with an internal template for Disqus comments, a popular commenting system for both static and dynamic websites. In order to effectively use Disqus, you will need to secure a Disqus "shortname" by [signing up for the free service][disqussignup].

    Configure Disqus

    To use Hugo's Disqus template, you first need to set a single value in your site's config.toml or config.yml:

    disqusShortname = "yourdiscussshortname"
    disqusShortname: "yourdiscussshortname"

    You also have the option to set the following in the front matter for a given piece of content:

    • disqus_identifier
    • disqus_title
    • disqus_url

    Use the Disqus Template

    To add Disqus, include the following line in templates where you want your comments to appear:

    {{ template "_internal/disqus.html" . }}

    Conditional Loading of Disqus Comments

    Users have noticed that enabling Disqus comments when running the Hugo web server on localhost (i.e. via hugo server) causes the creation of unwanted discussions on the associated Disqus account.

    You can create the following layouts/partials/disqus.html:

    {{< code file="layouts/partials/disqus.html" download="disqus.html" >}}

    <script type="text/javascript">

    (function() { // Don't ever inject Disqus on localhost--it creates unwanted // discussions from 'localhost:1313' on your Disqus account... if (window.location.hostname == "localhost") return;

    var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
    var disqus_shortname = '{{ .Site.DisqusShortname }}';
    dsq.src = '//' + disqus_shortname + '';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);

    })(); </script> Please enable JavaScript to view the comments powered by Disqus. comments powered by Disqus {{< /code >}}

    The if statement skips the initialization of the Disqus comment injection when you are running on localhost.

    You can then render your custom Disqus partial template as follows:

    {{ partial "disqus.html" . }}

    Alternative Templating Languages

    Ace Templates

    For template documentation, follow the links from the Ace project.

    • Ace templates must be named with the ace-suffix; e.g., list.ace
    • It's possible to use both Go templates and Ace templates side by side and even include one into the other
    • Full Go template syntax support, including all the useful helper template functions
    • Partials can be included both with the Ace and the Go template syntax. For example, the following two will have the same output in Ace:
      • = include partials/foo.html .
      • {{ partial "foo" . }}

    One noticeable difference between Ace and the other templating engines in Hugo is Ace's inheritance support through base and inner templates.

    In Hugo, the Ace base template will be chosen with the same rule set as for [Go base templates][].

    baseof.ace  list.ace  single.ace  single-baseof.ace

    {{% note %}} Note that the html suffix is needed even if the filename is suffixed ace. This does not work from inside a theme (issue #763). {{% /note %}}

    Some examples for the layout files above:

    • Home page: ./index.ace + ./_default/baseof.ace
    • Single page in the blog section: ./blog/single.ace + ./blog/baseof.ace
    • Single page in another section: ./_default/single.ace + ./_default/single-baseof.ace
    • Taxonomy page in any section: ./_default/list.ace + ./_default/baseof.ace

    {{% note %}} In most cases, one baseof.ace in _default will suffice. An Ace template without a reference to a base section (e.g., = content) will be handled as a standalone template. {{% /note %}}

    Amber Templates

    For Amber template documentation, follow the links from the Amber project.

    • Amber templates must be named with the Amber suffix; e.g., list.amber
    • Partials in Amber or HTML can be included with the Amber template syntax:
      • import ../partials/test.html
      • import ../partials/test_a.amber

    [Go base templates]: /templates/base/

    Template Debugging

    Here are some snippets you can add to your template to answer some common questions.

    These snippets use the printf function available in all Go templates. This function is an alias to the Go function, fmt.Printf.

    What Variables are Available in this Context?

    You can use the template syntax, $., to get the top-level template context from anywhere in your template. This will print out all the values under, .Site.

    {{ printf "%#v" $.Site }}

    This will print out the value of .Permalink:

    {{ printf "%#v" .Permalink }}

    This will print out a list of all the variables scoped to the current context (., aka ["the dot"][tempintro]).

    {{ printf "%#v" . }}

    When developing a homepage, what does one of the pages you're looping through look like?

    {{ range .Data.Pages }}
        {{/* The context, ".", is now each one of the pages as it goes through the loop */}}
        {{ printf "%#v" . }}
    {{ end }}

    {{% note ".Data.Pages on the Homepage" %}} .Data.Pages on the homepage is equivalent to .Site.Pages. {{% /note %}}

    Why Am I Showing No Defined Variables?

    Check that you are passing variables in the partial function:

    {{ partial "header" }}

    This example will render the header partial, but the header partial will not have access to any contextual variables. You need to pass variables explicitly. For example, note the addition of ["the dot"][tempintro].

    {{ partial "header" . }}

    The dot (.) is considered fundamental to understanding Hugo templating. For more information, see [Introduction to Hugo Templating][tempintro].

    [tempintro]: /templates/introduction/

    Functions Quick Reference

    Go templates are lightweight but extensible. Go itself supplies built-in functions, including comparison operators and other basic tools. These are listed in the Go template documentation. Hugo has added additional functions to the basic template logic.


    An alternative way of writing an if statement and then referencing the same value is to use with instead. with rebinds the context (.) within its scope and skips the block if the variable is absent or unset.

    The following example checks for a user-defined site variable called twitteruser. If the key-value is not set, the following will render nothing:

    {{< code file="layouts/partials/twitter.html" >}} {{with .Site.Params.twitteruser}} Twitter {{end}} {{< /code >}}


    where filters an array to only the elements containing a matching value for a given field.

    {{ range where .Data.Pages "Section" "post" }}
      {{ .Content }}
    {{ end }}

    It can be used by dot-chaining the second argument to refer to a nested element of a value.

    series: golang
    {{ range where .Site.Pages "Params.series" "golang" }}
       {{ .Content }}
    {{ end }}

    It can also be used with the logical operators !=, >=, in, etc. Without an operator, where compares a given field with a matching value equivalent to =.

    {{ range where .Data.Pages "Section" "!=" "post" }}
       {{ .Content }}
    {{ end }}

    The following logical operators are vailable with where:

    =, ==, eq : true if a given field value equals a matching value

    !=, <>, ne : true if a given field value doesn't equal a matching value

    >=, ge : true if a given field value is greater than or equal to a matching value

    >, gt : true if a given field value is greater than a matching value

    <=, le : true if a given field value is lesser than or equal to a matching value

    <, lt : true if a given field value is lesser than a matching value

    in : true if a given field value is included in a matching value; a matching value must be an array or a slice

    not in : true if a given field value isn't included in a matching value; a matching value must be an array or a slice

    intersect : true if a given field value that is a slice/array of strings or integers contains elements in common with the matching value; it follows the same rules as the intersect function.

    Use where with intersect

    {{ range where .Site.Pages ".Params.tags" "intersect" .Params.tags }}
      {{ if ne .Permalink $.Permalink }}
        {{ .Render "summary" }}
      {{ end }}
    {{ end }}

    You can also put the returned value of the where clauses into a variable:

    {{< code file="where-intersect-variables.html" >}} {{ $v1 := where .Site.Pages "Params.a" "v1" }} {{ $v2 := where .Site.Pages "Params.b" "v2" }} {{ $filtered := $v1 | intersect $v2 }} {{ range $filtered }} {{ end }} {{< /code >}}

    Use where with first

    The following grabs the first five content files in post using the default ordering for lists (i.e., weight => date):

    {{< code file="where-with-first.html" >}} {{ range first 5 (where .Data.Pages "Section" "post") }} {{ .Content }} {{ end }} {{< /code >}}

    Nest where Clauses

    You can also nest where clauses to drill down on lists of content by more than one parameter. The following first grabs all pages in the "blog" section and then ranges through the result of the first where clause and finds all pages that are not featured:

    {{ range where (where .Data.Pages "Section" "blog" ) ".Params.featured" "!=" "true" }}

    Unset Fields

    Filtering only works for set fields. To check whether a field is set or exists, you can use the operand nil.

    This can be useful to filter a small amount of pages from a large pool. Instead of set field on all pages, you can set field on required pages only.

    Only the following operators are available for nil

    • =, ==, eq: True if the given field is not set.
    • !=, <>, ne: True if the given field is set.
    {{ range where .Data.Pages ".Params.specialpost" "!=" nil }}
       {{ .Content }}
    {{ end }}


    The following examples pull from a content file with the following front matter:

    {{< code file="content/blog/" copy="false">}} +++ title = "The World's Greatest City" location = "Chicago IL" tags = ["pizza","beer","hot dogs"] +++ {{< /code >}}

    The following might be used as a partial within a single page template:

    {{< code file="layouts/partials/content-header.html" download="content-header.html" >}}


    {{ with .Params.location }} {{ end }} {{ with .Params.tags }} {{ end }} {{< /code >}}

    The preceding partial would then output to the rendered page as follows, assuming the page is being built with Hugo's default pretty URLs.

    {{< output file="/blog/greatest-city/index.html" >}}

    The World's Greatest City

    {{< /output >}}


    Note that upper can be applied in your templates in more than one way:

    {{ upper "BatMan" }} → "BATMAN"
    {{ "BatMan" | upper }} → "BATMAN"


    Example: Time Passed Since Last Modification

    This very simple one-liner uses now.Unix to calculate the amount of time that has passed between the .LastMod for the current page and the last build of the current page.

    {{< code file="time-passed.html" >}} {{ div (sub now.Unix .Lastmod.Unix) 86400 }} {{< /code >}}

    Since both values are integers, they can be subtracted and then divided by the number of seconds in a day (i.e., 60 * 60 * 24 == 86400).

    {{% note %}} Hugo's output is static. For the example above to be realistic, the site needs to be built every day. {{% /note %}}


    {{ uniq (slice 1 2 3 2) }}
    {{ slice 1 2 3 2 | uniq }}
    <!-- both return [1 2 3] -->


    Given two arrays (or slices) A and B, this function will return a new array that contains the elements or objects that belong to either A or to B or to both. The elements supported are strings, integers, and floats (only float64).

    {{ union (slice 1 2 3) (slice 3 4 5) }}
    <!-- returns [1 2 3 4 5] -->
    {{ union (slice 1 2 3) nil }}
    <!-- returns [1 2 3] -->
    {{ union nil (slice 1 2 3) }}
    <!-- returns [1 2 3] -->
    {{ union nil nil }}
    <!-- returns an error because both arrays/slices have to be of the same type -->

    This is also very useful to use as OR filters when combined with where:

    {{ $pages := where .Site.RegularPages "Type" "not in" (slice "page" "about") }}
    {{ $pages := $pages | union (where .Site.RegularPages "Params.pinned" true) }}
    {{ $pages := $pages | intersect (where .Site.RegularPages "Params.images" "!=" nil) }}

    The above fetches regular pages not of page or about type unless they are pinned. And finally, we exclude all pages with no images set in Page params.

    See intersect for AND.


    Since Go templates are HTML-aware, truncate will intelligently handle normal strings vs HTML strings:

    {{ "<em>Keep my HTML</em>" | safeHTML | truncate 10 }}` → <em>Keep my …</em>`

    {{% note %}} If you have a raw string that contains HTML tags you want to remain treated as HTML, you will need to convert the string to HTML using the safeHTML template function before sending the value to truncate. Otherwise, the HTML tags will be escaped when passed through the truncate function. {{% /note %}}


    {{ trim "++Batman--" "+-" }} → "Batman"

    trim requires the second argument, which tells the function specifically what to remove from the first argument. There is no default value for the second argument, so the following usage will not work:

    {{ trim .Inner}}

    Instead, the following example tells trim to remove extra new lines from the content contained in the shortcode .Inner variable:

    {{ trim .Inner "\n" }}

    {{% note %}} Go templates also provide a simple method for trimming whitespace from either side of a Go tag by including a hyphen (-). {{% /note %}}


    {{title "BatMan"}}` → "Batman"


    time converts a timestamp string into a time.Time structure so you can access its fields:

    {{ time "2016-05-28" }} → "2016-05-28T00:00:00Z"
    {{ (time "2016-05-28").YearDay }} → 149
    {{ mul 1000 (time "2016-05-28T10:30:00.00+10:00").Unix }} → 1464395400000, or Unix time in milliseconds

    Example: Using time to get Month Index

    The following example takes a UNIX timestamp---set as utimestamp: "1489276800" in a content's front matter---converts the timestamp (string) to an integer using the int function, and then uses printf to convert the Month property of time into an index.

    The following example may be useful when setting up multilingual sites:

    {{< code file="unix-to-month-integer.html" >}} {{$time := time (int .Params.addDate)}} => $time = 1489276800 {{$time.Month}} => "March" {{$monthindex := printf "%d" $time.Month }} => $monthindex = 3 {{< /code >}}


    It normally takes two parameters: start and length. It can also take one parameter: start, i.e. length is omitted, in which case the substring starting from start until the end of the string will be returned.

    To extract characters from the end of the string, use a negative start number.

    In addition, borrowing from the extended behavior described at substr, if length is given and is negative, that number of characters will be omitted from the end of string.

    {{substr "BatMan" 0 -3}} → "Bat"
    {{substr "BatMan" 3 3}} → "Man"


    • {{string "BatMan"}} → "BatMan"


    • {{split "tag1,tag2,tag3" "," }} → ["tag1" "tag2" "tag3"]


    A sorted array of map values will be returned with the keys eliminated. There are two optional arguments: sortByField and sortAsc. If left blank, sort will sort by keys (for maps) in ascending order as its default behavior.

    #tags: [ "tag3", "tag1", "tag2" ]
    // Site config
        "firstName"  = "Derek"
        "lastName"   = "Perkins"
        "firstName"  = "Joe"
        "lastName"   = "Bergevin"
        "firstName"  = "Tanner"
        "lastName"   = "Linsley"
    // Use default sort options - sort by key / ascending
    Tags: {{ range sort .Params.tags }}{{ . }} {{ end }}
    → Outputs Tags: tag1 tag2 tag3
    // Sort by value / descending
    Tags: {{ range sort .Params.tags "value" "desc" }}{{ . }} {{ end }}
    → Outputs Tags: tag3 tag2 tag1
    // Use default sort options - sort by value / descending
    Authors: {{ range sort .Site.Params.authors }}{{ .firstName }} {{ end }}
    → Outputs Authors: Derek Joe Tanner
    // Use default sort options - sort by value / descending
    Authors: {{ range sort .Site.Params.authors "lastName" "desc" }}{{ .lastName }} {{ end }}
    → Outputs Authors: Perkins Linsley Bergevin


    For example, 1 and 4 creates a slice including elements 1 through 3. The end index can be omitted; it defaults to the string's length.

    • {{slicestr "BatMan" 3}} → "Man"
    • {{slicestr "BatMan" 0 3}} → "Bat"


    One use case is the concatenation of elements in combination with the delimit function:

    {{< code file="slice.html" >}} {{ delimit (slice "foo" "bar" "buzz") ", " }}

    {{< /code >}}


    {{ "cats" | singularize }} → "cat"

    See also the .Data.Singular taxonomy variable for singularizing taxonomy names.


    {{< code file="shuffle-input.html" >}}

    {{ shuffle (seq 1 5) }}
    {{ shuffle (slice "foo" "bar" "buzz") }}
    {{< /code >}}

    This example would return the following:

    {{< output file="shuffle-output.html" >}}

    2 5 3 1 4
    buzz foo bar
    {{< /output >}}

    This example also makes use of the slice and seq functions.


    sha1 hashes the given input and returns its SHA1 checksum.

    {{ sha1 "Hello world, gophers!" }}
    <!-- returns the string "c8b5b0e33d408246e30f53e32b8f7627a7a649d4" -->

    sha256 hashes the given input and returns its SHA256 checksum.

    {{ sha256 "Hello world, gophers!" }}
    <!-- returns the string "6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46" -->


    It's named and used in the model of GNU's seq.

    3 → 1, 2, 3
    1 2 4 → 1, 3
    -3 → -1, -2, -3
    1 4 → 1, 2, 3, 4
    1 -2 → 1, 0, -1, -2

    Example: seq with range and after

    You can use seq in combination with range and after. The following will return 19 elements:

    {{ range after 1 (seq 20)}}
    {{ end }}

    However, when ranging with an index, the following may be less confusing in that $indexStartingAt1 and $num will return 1,2,3 ... 20:

    {{ range $index, $num := (seq 20) }}
    $indexStartingAt1 := (add $index 1)
    {{ end }}


    In most cases you can do well without Scratch, but there are some use cases that aren't solvable with Go's templates without Scratch's help, due to scoping issues.

    Scratch is added to both Page and Shortcode -- with following methods:

    • Set and Add takes a key and the value to add.
    • Get returns the value for the key given.
    • SetInMap takes a key, mapKey and value
    • GetSortedMapValues returns array of values from key sorted by mapKey

    Set and SetInMap can store values of any type.

    For single values, Add accepts values that support Go's + operator. If the first Add for a key is an array or slice, the following adds will be appended to that list.

    The scope of the backing data is global for the given Page or Shortcode, and spans partial and shortcode includes.

    Note that .Scratch from a shortcode will return the shortcode's Scratch, which in most cases is what you want. If you want to store it in the page scroped Scratch, then use .Page.Scratch.

    Sample usage

    The usage is best illustrated with some samples:

    {{ $.Scratch.Add "a1" 12 }}
    {{ $.Scratch.Get "a1" }} {{/* => 12 */}}
    {{ $.Scratch.Add "a1" 1 }}
    {{ $.Scratch.Get "a1" }} // {{/* => 13 */}}
    {{ $.Scratch.Add "a2" "AB" }}
    {{ $.Scratch.Get "a2" }} {{/* => AB */}}
    {{ $.Scratch.Add "a2" "CD" }}
    {{ $.Scratch.Get "a2" }} {{/* => ABCD */}}
    {{ $.Scratch.Add "l1" (slice "A" "B") }}
    {{ $.Scratch.Get "l1" }} {{/* => [A B]  */}}
    {{ $.Scratch.Add "l1" (slice "C" "D") }}
    {{ $.Scratch.Get "l1" }} {{/* => [A B C D] */}}
    {{ $.Scratch.Set "v1" 123 }}
    {{ $.Scratch.Get "v1" }}  {{/* => 123 */}}
    {{ $.Scratch.SetInMap "a3" "b" "XX" }}
    {{ $.Scratch.SetInMap "a3" "a" "AA" }}
    {{ $.Scratch.SetInMap "a3" "c" "CC" }}
    {{ $.Scratch.SetInMap "a3" "b" "BB" }}
    {{ $.Scratch.GetSortedMapValues "a3" }} {{/* => []interface {}{"AA", "BB", "CC"} */}}

    {{% note %}} The examples above uses the special $ variable, which refers to the top-level node. This is the behavior you most likely want, and will help remove some confusion when using Scratch inside page range loops -- and you start inadvertently calling the wrong Scratch. But there may be use cases for {{ .Scratch.Add "key" "some value" }}. {{% /note %}}


    safeURL declares the provided string as a "safe" URL or URL substring (see RFC 3986). A URL like javascript:checkThatFormNotEditedBeforeLeavingPage() from a trusted source should go in the page, but by default dynamic javascript: URLs are filtered out since they are a frequently exploited injection vector.

    Without safeURL, only the URI schemes http:, https: and mailto: are considered safe by Go templates. If any other URI schemes (e.g., irc: and javascript:) are detected, the whole URL will be replaced with #ZgotmplZ. This is to "defang" any potential attack in the URL by rendering it useless.

    The following examples use a site config.toml with the following menu entry:

    {{< code file="config.toml" copy="false" >}} [[menu.main]] name = "IRC: #golang at freenode" url = "irc://" {{< /code >}}

    The following is an example of a sidebar partial that may be used in conjunction with the preceding front matter example:

    {{< code file="layouts/partials/bad-url-sidebar-menu.html" copy="false" >}}

    {{< /code >}}

    This partial would produce the following HTML output:

    {{< output file="bad-url-sidebar-menu-output.html" >}}

    {{< /output >}}

    The odd output can be remedied by adding | safeURL to our .Title page variable:

    {{< code file="layouts/partials/correct-url-sidebar-menu.html" copy="false" >}}

    {{< /code >}}

    With the .URL page variable piped through safeURL, we get the desired output:

    {{< output file="correct-url-sidebar-menu-output.html" >}}

    • IRC: #golang at freenode
    {{< /output >}}


    In this context, safe means the string encapsulates a known safe EcmaScript5 Expression (e.g., (x + y * z())).

    Template authors are responsible for ensuring that typed expressions do not break the intended precedence and that there is no statement/expression ambiguity as when passing an expression like { foo:bar() }\n['foo'](), which is both a valid expression and a valid program with a very different meaning.

    Example: Given hash = "619c16f" defined in the front matter of your .md file:

    • <script>var form_{{ .Params.hash | safeJS }};…</script><script>var form_619c16f;…</script>
    • <script>var form_{{ .Params.hash }};…</script><script>var form_"619c16f";…</script>


    Example: Given a site-wide config.toml that contains this menu entry:

        name = "IRC: #golang at freenode"
        url = "irc://"
    • <a href="{{ .URL }}"><a href="#ZgotmplZ">
    • <a {{ printf "href=%q" .URL | safeHTMLAttr }}><a href="irc://">


    It should not be used for HTML from a third-party, or HTML with unclosed tags or comments.

    Given a site-wide config.toml with the following copyright value:

    copyright = "© 2015 Jane Doe.  <a href=\"\">Some rights reserved</a>."

    {{ .Site.Copyright | safeHTML }} in a template would then output:

    © 2015 Jane Doe.  <a href="">Some rights reserved</a>.

    However, without the safeHTML function, html/template assumes .Site.Copyright to be unsafe and therefore escapes all HTML tags and renders the whole string as plain text:

    <p>© 2015 Jane Doe.  &lt;a href=&#34; by/4.0/&#34;&gt;Some rights reserved&lt;/a&gt;.</p>


    In this context, safe means CSS content that matches any of the following:

    1. The CSS3 stylesheet production, such as p { color: purple }.
    2. The CSS3 rule production, such as a[href=~"https:"].foo#bar.
    3. CSS3 declaration productions, such as color: red; margin: 2px.
    4. The CSS3 value production, such as rgba(0, 0, 255, 127).

    Example: Given style = "color: red;" defined in the front matter of your .md file:

    • <p style="{{ | safeCSS }}">…</p><p style="color: red;">…</p>
    • <p style="{{ }}">…</p><p style="ZgotmplZ">…</p>

    {{% note "ZgotmplZ" %}} "ZgotmplZ" is a special value that indicates that unsafe content reached a CSS or URL context. {{% /note %}}


    {{ replaceRE "^https?://([^/]+).*" "$1" "" }}` → ""
    {{ "" | replaceRE "^https?://([^/]+).*" "$1" }}` → ""

    {{% note %}} Hugo uses Golang's Regular Expression package, which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the GitHub wiki for re2.

    If you are just learning RegEx, or at least Golang's flavor, you can practice pattern matching in the browser at {{% /note %}}


    `{{ replace "Batman and Robin" "Robin" "Catwoman" }}`
    → "Batman and Catwoman"


    The view is an alternative layout and should be a file name that points to a template in one of the locations specified in the documentation for Content Views.

    This function is only available when applied to a single piece of content within a list context.

    This example could render a piece of content using the content view located at /layouts/_default/summary.html:

    {{ range .Data.Pages }}
        {{ .Render "summary"}}
    {{ end }}


    Both absURL and relURL consider the configured value of baseURL in your site's config file. Given a baseURL set to

    {{ "mystyle.css" | absURL }} → ""
    {{ "mystyle.css" | relURL }} → "/hugo/mystyle.css"
    {{ "" | relURL }} →  ""
    {{ "" | absURL }} →  ""

    The last two examples may look strange but can be very useful. For example, the following shows how to use absURL in JSON-LD structured data for SEO where some of your images for a piece of content may or may not be hosted locally:

    {{< code file="layouts/partials/schemaorg-metadata.html" download="schemaorg-metadata.html" >}}

    <script type="application/ld+json"> { "@context" : "", "@type" : "BlogPosting", "image" : {{ apply .Params.images "absURL" "." }} } </script>

    {{< /code >}}

    The above uses the apply function and also exposes how the Go template parser JSON-encodes objects inside <script> tags. See the safeJS template function for examples of how to tell Hugo not to escape strings inside of such tags.

    {{% note "Ending Slash" %}} absURL and relURL are smart about missing slashes, but they will not add a closing slash to a URL if it is not present. {{% /note %}}


    ref and relRef look up a content page by relative path (relref) or logical name (ref) to return the permalink. Both functions require a Page object (usually satisfied with a "."):

    {{ relref . "" }}

    These functions are used in two of Hugo's built-in shortcodes. You can see basic usage examples of both ref and relref in the shortcode documentation.

    For an extensive explanation of how to leverage ref and relref for content management, see Cross References.


    absLangURL and relLangURL functions are similar to their absURL and relURL relatives but will add the correct language prefix when the site is configured with more than one language. (See Configuring Multilingual.)

    So for a site baseURL set to and the current language is en:

    {{ "blog/" | absLangURL }} → ""
    {{ "blog/" | relLangURL }} → "/hugo/en/blog/"


    ref and relRef look up a content page by relative path (relref) or logical name (ref) to return the permalink. Both functions require a Page object (usually satisfied with a "."):

    {{ relref . "" }}

    These functions are used in two of Hugo's built-in shortcodes. You can see basic usage examples of both ref and relref in the shortcode documentation.

    For an extensive explanation of how to leverage ref and relref for content management, see Cross References.


    Note that the filename must be relative to the current project working directory.

    So, if you have a file with the name README.txt in the root of your project with the content Hugo Rocks!:

    {{readFile "README.txt"}} → "Hugo Rocks!"

    For more information on using readDir and readFile in your templates, see Local File Templates.


    If your current project working directory has a single file named README.txt:

    {{ range (readDir ".") }}{{ .Name }}{{ end }} → "README.txt"

    For more information on using readDir and readFile in your templates, see Local File Templates.


    Just like in the Go programming language, Go and Hugo templates make heavy use of range to iterate over a map, array or slice.

    range is fundamental to templating in Hugo. (See the Introduction to Hugo Templates for more examples.


    querify takes a set of key-value pairs and returns a query string that can be appended to a URL. E.g.

    The following example creates a link to a search results page on Google.

    <a href="{{ (querify "q" "test" "page" 3) | safeURL }}">Search</a>

    This example renders the following HTML:

    <a href="">Search</a>


    See the go doc for additional information.

    {{ i18n ( printf "combined_%s" $var ) }}
    {{ printf "formatted %.2f" 3.1416 }}


    {{ "cat" | pluralize }} → "cats"


    {{ "<b>BatMan</b>" | plainify }} → "BatMan"

    See also the .PlainWords, .Plain, and .RawContent page variables.


    The partialCached template function can offer significant performance gains for complex templates that don't need to be re-rendered on every invocation. Here is the simplest usage:

    {{ partialCached "footer.html" . }}

    You can also pass additional parameters to partialCached to create variants of the cached partial. For example, if you have a complex partial that should be identical when rendered for pages within the same section, you could use a variant based upon section so that the partial is only rendered once per section:

    {{< code file="partial-cached-example.html" >}} {{ partialCached "footer.html" . .Section }} {{< /code >}}

    If you need to pass additional parameters to create unique variants, you can pass as many variant parameters as you need:

    {{ partialCached "footer.html" . .Params.province }}

    Note that the variant parameters are not made available to the underlying partial template. They are only use to create a unique cache key.


    In Hugo, you can declare site-wide params (i.e. in your configuration), as well as params for individual pages.

    A common use case is to have a general value for the site and a more specific value for some of the pages (e.g., an image).

    You can use the .Param method to call these values into your template. The following will first look for an image param in a specific content's front matter. If not found, Hugo will look for an image param in your site's configuration:

    $.Param "image"

    {{% note %}} The Param method may not consider empty strings in a content's front matter as "not found." If you are setting preconfigured front matter fields to empty strings using Hugo's archetypes, it may be best to use the default function instead of Param. See the related issue on GitHub. {{% /note %}}


    See time.Time.

    For example, building your site on June 24, 2017 with the following templating:

        <small>&copy; {{ now.Format "2006"}}</small>

    Which will produce the following:

        <small>&copy; 2017</small>

    The above example uses the .Format function, which page includes a full listing of date formatting using Golang's layout string.

    {{% note %}} Older Hugo themes may use the deprecated .Now (uppercase). Be sure to use the lowercase .now in your templating. {{% /note %}}


    {{ if ne .Section "blog" }}current{{ end }}


    {{ md5 "Hello world, gophers!" }}
    <!-- returns the string "b3029f756f98f79e7f1b7f1d1f0dd53b" -->

    This can be useful if you want to use Gravatar for generating a unique avatar:

    <img src="{{ md5 "" }}?s=100&d=identicon">


    There are 6 basic mathematical operators that can be used in Hugo templates:

    Function Description Example
    add Adds two integers. {{add 1 2}} → 3
    div Divides two integers. {{div 6 3}} → 2
    mod Modulus of two integers. {{mod 15 3}} → 0
    modBool Boolean of modulus of two integers. Evaluates to true if = 0. {{modBool 15 3}} → true
    mul Multiplies two integers. {{mul 2 3}} → 6
    sub Subtracts two integers. {{sub 3 2}} → 1

    Use add with Strings

    You can also use the add function with strings. You may like this functionality in many use cases, including creating new variables by combining page- or site-level variables with other strings.

    For example, social media sharing with Twitter Cards requires the following meta link in your site's <head> to display Twitter's ["Summary Card with Large Image"][twtsummary]:

    <meta name="twitter:image" content="">

    Let's assume you have an image field in the front matter of each of your content files:

    title: My Post
    image: my-post-image.jpg

    You can then concatenate the image value (string) with the path to your images directory in static and leverage a URL-related templating function for increased flexibility:

    {{< code file="partials/head/twitter-card.html" >}} {{$socialimage := add "images/" .Params.image}}

    {{< /code >}}

    {{% note %}} The add example above makes use of the absURL function. absURL and its relative companion relURL is the recommended way to construct URLs in Hugo. {{% /note %}}



    {{ .Title | markdownify }}


    {{ if lt 5 10 }}true{{ end }}


    {{lower "BatMan"}} → "batman"


    len is a built-in function in Golang that returns the length of a variable according to its type. From the Golang documentation:

    Array: the number of elements in v.

    Pointer to array: the number of elements in *v (even if v is nil).

    Slice, or map: the number of elements in v; if v is nil, len(v) is zero.

    String: the number of bytes in v.

    Channel: the number of elements queued (unread) in the channel buffer; if v is nil, len(v) is zero.

    len is also considered a fundamental function for Hugo templating.

    len Example 1: Longer Headings

    You may want to append a class to a heading according to the length of the string therein. The following templating checks to see if the title's length is greater than 80 characters and, if so, adds a long-title class to the <h1>:

    {{< code file="check-title-length.html" >}}

    {{.Title}} {{< /code >}}

    len Example 2: Counting Pages with where

    The following templating uses [where][] in conjunction with len to figure out the total number of content pages in a posts section:

    {{< code file="how-many-posts.html" >}} {{ $posts := (where .Site.RegularPages "Section" "==" "post") }} {{ $postCount := len $posts }} {{< /code >}}

    Note the use of .RegularPages, a site variable that counts all regular content pages but not the pages used to add front matter and content to list templates.

    [where]: /functions/where/


    {{ if le 5 10 }}true{{ end }}


    {{ range last 10 .Data.Pages }}
        {{ .Render "summary" }}
    {{ end }}


    {{ dict "title" .Title "content" .Plain | jsonify }}

    See also the .PlainWords, .Plain, and .RawContent page variables.


    Takes either a slice, array, or channel and an index or a map and a key as input.

    {{ if isset .Params "project_url" }} {{ index .Params "project_url" }}{{ end }}

    {{% warning %}} All site-level configuration keys are stored as lower case. Therefore, a myParam key-value set in your site configuration file needs to be accessed with {{if isset .Site.Params "myparam"}} and not with {{if isset .Site.Params "myParam"}}. Note that you can still access the same config key with .Site.Params.myParam or .Site.Params.myparam, for example, when using with. {{% /warning %}}


    Used in menu templates.


    The elements supported are strings, integers, and floats (only float64).

    A useful example of intersect functionality is a "related posts" block. isset allows us to create a list of links to other posts that have tags that intersect with the tags in the current post.

    The following is an example of a "related posts" partial template that could be added to a single page template:

    {{< code file="layouts/partials/related-posts.html" download="related-posts.html" >}}

      {{ $page_link := .Permalink }} {{ $tags := .Params.tags }} {{ range .Site.Pages }} {{ $page := . }} {{ $has_common_tags := intersect $tags .Params.tags | len | lt 0 }} {{ if and $has_common_tags (ne $page_link $page.Permalink) }}
    • {{ $page.Title }}
    • {{ end }} {{ end }}
    {{< /code >}}

    This is also very useful to use as AND filters when combined with where:

    {{ $pages := where .Site.RegularPages "Type" "not in" (slice "page" "about") }}
    {{ $pages := $pages | union (where .Site.RegularPages "Params.pinned" true) }}
    {{ $pages := $pages | intersect (where .Site.RegularPages "Params.images" "!=" nil) }}

    The above fetches regular pages not of page or about type unless they are pinned. And finally, we exclude all pages with no images set in Page params.

    See union for OR.


    Useful for turning strings into numbers.

    {{ int "123" }} → 123


    From the Godocs:

    Returns the result of indexing its first argument by the following arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each indexed item must be a map, slice, or array.

    In Go templates, you can't access array, slice, or map elements directly the same way you would in Go. For example, $.Site.Data.authors[.Params.authorkey] isn't supported syntax.

    Instead, you have to use index, a function that handles the lookup for you.

    Example: Load Data from a Path Based on Front Matter Params

    Assume you want to add a location = "" field to your front matter for every article written in content/vacations/. You want to use this field to populate information about the location at the bottom of the article in your single.html template. You also have a directory in data/locations/ that looks like the following:

    └── data
        └── locations
            ├── abilene.toml
            ├── chicago.toml
            ├── oslo.toml
            └── provo.toml

    Here is an example of the data inside data/locations/oslo.toml:

    website = ""
    pop_city = 658390
    pop_metro = 1717900

    The example we will use will be an article on Oslo, which front matter should set to exactly the same name as the corresponding file name in data/locations/:

    title = "My Norwegian Vacation"
    location = "oslo"

    The content of oslo.toml can be accessed from your template using the following node path: .Site.Data.locations.oslo. However, the specific file you need is going to change according to the front matter.

    This is where the index function is needed. index takes 2 parameters in this use case:

    1. The node path
    2. A string corresponding to the desired data; e.g.—
    {{ index .Site.Data.locations “oslo” }}

    The variable for .Params.location is a string and can therefore replace oslo in the example above:

    {{ index .Site.Data.authors }}
    => map[website: pop_city:658390 pop_metro:1717900]

    Now the call will return the specific file according to the location specified in the content's front matter, but you will likely want to write specific properties to the template. You can do this by continuing down the node path via dot notation (.):

    {{ (index .Site.Data.locations .Params.location).pop_city }}
    => 658390


    The elements supported are strings, integers and floats, although only float64 will match as expected.

    In addition, in can also check if a substring exists in a string.

    {{ if in .Params.tags "Git" }}Follow me on GitHub!{{ end }}
    {{ if in "this string contains a substring" "substring" }}Substring found!{{ end }}

    {{ with (imageConfig "favicon.ico") }}
    favicon.ico: {{.Width}} x {{.Height}}
    {{ end }}


    This translates a piece of content based on your i18n/en-US.yaml (and similar) files. You can use the go-i18n tools to manage your translations. The translations can exist in both the theme and at the root of your repository.

    {{ i18n "translation_id" }}

    {{% note "Alias T" %}} T is an alias to i18n. E.g. {{ T "translation_id" }}. {{% /note %}}

    For more information about string translations, see Translation of Strings in Multilingual Mode.


    If the input is either an int64 value or the string representation of an integer, humanize returns the number with the proper ordinal appended.

    {{humanize "my-first-post"}} → "My first post"
    {{humanize "myCamelPost"}} → "My camel post"
    {{humanize "52"}} → "52nd"
    {{humanize 103}} → "103rd"


    htmlUnescape returns the given string with HTML escape codes un-escaped.

    Remember to pass the output of this to safeHTML if fully un-escaped characters are desired. Otherwise, the output will be escaped again as normal.

    {{ htmlUnescape "Hugo &amp; Caddy &gt; Wordpress &amp; Apache" }} → "Hugo & Caddy > Wordpress & Apache"


    In the result & becomes &amp; and so on. It escapes only: <, >, &, ' and ".

    {{ htmlEscape "Hugo & Caddy > Wordpress & Apache" }} → "Hugo &amp; Caddy &gt; Wordpress &amp; Apache"


    highlight is used in Hugo's built-in highlight shortcode.

    See Installing Hugo for more information on Pygments or Syntax Highlighting for more options on how to add syntax highlighting to your code blocks with Hugo.


    Used in menu templates.


    Used in menu templates.


    • {{ hasPrefix "Hugo" "Hu" }} → true


    {{ if gt 10 5 }}true{{ end }}


    Takes a string containing the name of the variable as input. Returns an empty string if the variable is not set, otherwise returns the value of the variable.

    {{ getenv "HOME" }}

    {{% note %}} In Unix-like environments, the variable must also be exported in order to be seen by hugo. {{% /note %}}


    .Get is specifically used when creating your own shortcode template.


    {{ if ge 10 5 }}true{{ end }}


    .Format will format date values defined in your front matter and can be used as a property on the following page variables:

    • .PublishDate
    • .Date
    • .LastMod

    Assuming a key-value of date: 2017-03-03 in a content file's front matter, your can run the date through .Format followed by a layout string for your desired output at build time:

    {{ .PublishDate.Format "January 2, 2006" }} => March 3, 2017

    For formatting any string representations of dates defined in your front matter, see the dateFormat function, which will still leverage the Golang layout string explained below but uses a slightly different syntax.

    Go's Layout String

    Hugo templates format your dates via layout strings that point to a specific reference time:

    Mon Jan 2 15:04:05 MST 2006

    While this may seem arbitrary, the numerical value of MST is 07, thus making the layout string a sequence of numbers.

    Here is a visual explanation taken directly from the Go docs:

     Jan 2 15:04:05 2006 MST
    => 1 2  3  4  5    6  -7

    Hugo Date and Time Templating Reference

    The following examples show the layout string followed by the rendered output.

    The examples were rendered and tested in CST and all point to the same field in a content file's front matter:

    date: 2017-03-03T14:15:59-06:00

    .Date (i.e. called via page variable) : Returns: 2017-03-03 14:15:59 -0600 CST

    "Monday, January 2, 2006" : Returns: Friday, March 3, 2017

    "Mon Jan 2 2006" : Returns: Fri Mar 3 2017

    "January 2nd" : Returns: March 3rd

    "January 2006" : Returns: March 2017

    "2006-01-02" : Returns: 2017-03-03

    "Monday" : Returns: Friday

    "02 Jan 06 15:04 MST" (RFC822) : Returns: 03 Mar 17 14:15 CST

    "02 Jan 06 15:04 -0700" (RFC822Z) : Returns: 03 Mar 17 14:15 -0600

    "Mon, 02 Jan 2006 15:04:05 MST" (RFC1123) : Returns: Fri, 03 Mar 2017 14:15:59 CST

    "Mon, 02 Jan 2006 15:04:05 -0700" (RFC339) : Returns: Fri, 03 Mar 2017 14:15:59 -0600

    Cardinal Numbers and Ordinal Abbreviations

    Spelled-out cardinal numbers (e.g. "one", "two", and "three") and ordinal abbreviations (i.e., with shorted suffixes like "1st", "2nd", and "3rd") are not currently supported:

    {{.Date.Format "Jan 2nd 2006"}}

    Hugo assumes you want to append nd as a string to the day of the month and outputs the following:

    Mar 3nd 2017