The documentation of the Hugo static site generator in one long page. LOOKING FOR MAINTAINER. Look at forks for improvements.
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.
Hugo is not your average static site generator.
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.
{{< youtube “CdiDYZ51a2o” >}}
In technical terms, Hugo takes a source directory of files and templates and uses these as input to create a complete website.
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.
See what’s coming next in the Hugo roadmap.
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.
To track Hugo’s progress, see our GitHub Milestones.
In no particular order, here are some other features currently being worked on:
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.
{{% 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
http://www.apache.org/licenses/LICENSE-2.0
Terms and Conditions for use, reproduction, and distribution
“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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
END OF TERMS AND CONDITIONS
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
http://www.apache.org/licenses/LICENSE-2.0
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 >}}
If this is your first time using Hugo and you’ve already installed Hugo on your machine, we recommend the 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 %}}
{{% note %}}
Homebrew
, a package manager for macOS
, can be installed from brew.sh. See install if you are running Windows etc.
{{% /note %}}
brew install hugo
To verify your new install:
hugo version
{{< asciicast HDlKrUrbfT7yiWsbd6QoxzRTN >}}
hugo new site quickstart
The above will create a new Hugo site in a folder named quickstart
.
{{< asciicast 1PH9A2fs14Dnyarx5v8OMYQer >}}
See themes.gohugo.io for a list of themes to consider. This quickstart uses the beautiful Ananke theme.
cd quickstart;\
git init;\
git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke;\
# Edit your config.toml configuration file
# and add the Ananke theme.
echo 'theme = "ananke"' >> config.toml
{{< asciicast WJM2LEZQs8VRhNeuZ5NiGPp9I >}}
hugo new posts/my-first-post.md
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 127.0.0.1)
Press Ctrl+C to stop
Navigate to your new site at http://localhost:1313/.
Your new site already looks great, but you will want to tweak it a little before you release it to the public.
Open up config.toml
in a text editor:
baseURL = "http://example.org/"
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 >}}
{{% 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:
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 https://golang.org/doc/install/source for the full set of supported combinations of target operating systems and compilation architectures.
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.
If you are on macOS and using Homebrew, you can install Hugo with the following one-liner:
{{< code file=“install-with-homebrew.sh” >}}
brew install hugo
{{< /code >}}
For more detailed explanations, read the installation guides that follow for installing on macOS and 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 >}}
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.
{{< code file=“from-gh.sh” >}}
go get github.com/kardianos/govendor
govendor get github.com/gohugoio/hugo
go install github.com/gohugoio/hugo
{{< /code >}}
govendor get
will fetch Hugo and all its dependent libraries to $GOPATH/src/github.com/gohugoio/hugo
, 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 %}}
~/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.)There are three ways to install Hugo on your Mac
brew
utilityThere is no “best” way to install Hugo on your Mac. You should use the method that works best for your use case.
There are pros and cons to each of the aforementioned methods:
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.
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.
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 %}}
brew
if you haven’t alreadyGo to the brew
website, https://brew.sh/, and follow the directions there. The most important step is the installation from the command line:
{{< code file=“install-brew.sh” >}}
ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
{{< /code >}}
brew
Command to Install hugo
Installing Hugo using brew
is as easy as the following:
{{< code file=“install-brew.sh” >}}
brew install hugo
{{< /code >}}
If Homebrew is working properly, you should see something similar to the following:
==> Downloading https://homebrew.bintray.com/bottles/hugo-0.21.sierra.bottle.tar.gz
######################################################################### 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
/usr/local/bin/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
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:
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.
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.
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.
Open https://github.com/gohugoio/hugo/releases in your browser.
Find the current release by scrolling down and looking for the green tag that reads “Latest Release.”
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.
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.
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/README.md
-rwxrwxrwx 0 0 0 0 Jan 30 18:48 hugo_X.Y_osx-64bit/LICENSE.md
The .md
files are documentation for Hugo. The other file is the executable.
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 ./LICENSE.md
x ./README.md
# 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
/Users/USERNAME/bin/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.
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
If you want to compile a specific version of Hugo, go to https://github.com/gohugoio/hugo/releases 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 https://github.com/gohugoio/hugo
{{% 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 %}}
Make the directory containing the source your working directory and then fetch Hugo’s dependencies:
mkdir -p src/github.com/gohugoio
ln -sf $(pwd) src/github.com/gohugoio/hugo
# 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.
C:\Hugo\Sites
as the starting point for your new project.C:\Hugo\bin
to store executable files.You’ll need a place to store the Hugo executable, your content, and the generated Hugo website:
C:\Hugo
, assuming you want Hugo on your C drive, although this can go anywhereC:\Hugo\bin
C:\Hugo\Sites
..\Hugo\bin
folder.hugo
executable will be named as hugo_hugo-version_platform_arch.exe
. Rename the executable to hugo.exe
for ease of use.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.C:\Hugo\bin
folder.C:\Hugo\bin
folder – Windows will do this by default unless you tell it to extract somewhere else.hugo_0.18_windows_amd64.exe
), license.md
, and readme.md
. (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:
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.{{% 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 %}}
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.
Run a few commands to verify that the executable is ready to run, and then build a sample site to get started.
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 https://gohugo.io/.
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
C:\Hugo\Sites>
Run the command to generate a new site. I’m using example.com
as the name of the site.
C:\Hugo\Sites> hugo new site example.com
You should now have a directory at C:\Hugo\Sites\example.com
. Change into that directory and list the contents. You should get output similar to the following:
C:\Hugo\Sites>cd example.com
C:\Hugo\Sites\example.com>dir
Directory of C:\hugo\sites\example.com
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
@dhersam has created a nice video on common issues:
{{< youtube c8fJIRNChmU >}}
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 provide a hugo
version via apt-get
:
sudo apt-get install hugo
man
pagesYou 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
See the related discussion in the Hugo forums.
Upgrading Hugo is as easy as downloading and replacing the executable you’ve placed in your PATH
.
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.
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.
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.
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 http://gohugo.io/.
Usage:
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
Flags:
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
-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
hugo
CommandThe 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:
hugo
0 draft content
0 future content
99 pages created
0 paginator pages created
16 tags created
0 groups created
in 90 ms
Hugo allows you to set draft
, publishdate
, and even expirydate
in your content’s front matter. By default, Hugo will not publish:
publishdate
valuedraft: true
statusexpirydate
valueAll 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:
--buildFuture
--buildDrafts
--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 %}}
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
Or…
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
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 %}}
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.
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
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
hugo new
command.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
content
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
layouts
.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
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 %}}
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.
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:
./config.toml
./config.yaml
./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.
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:
baseURL: “https://yoursite.example.com/”
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 >}}
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.
archetypeDir: “archetypes”
baseURL: “”
buildDrafts: false
buildFuture: false
buildExpired: false
relativeURLs: false
canonifyURLs: false
config: “config.toml”
contentDir: “content”
dataDir: “data”
defaultExtension: “html”
defaultLayout: “post”
defaultContentLanguage: “en”
defaultContentLanguageInSubdir: false
disableLiveReload: false
disableRSS: false
disableSitemap: false
enableGitInfo: false
enableRobotsTXT: false
disable404: false
disableHugoGeneratorInject: false
disableKinds: []
disablePathToLower: false “”
enableEmoji: false
enableMissingTranslationPlaceholders: false
footnoteAnchorPrefix: “”
footnoteReturnLinkContents: “”
googleAnalytics: “”
hasCJKLanguage: false
languageCode: “”
layoutDir: “layouts”
log: false
logFile: “”
metaDataFormat: “toml”
newContentEditor: “”
noChmod: false
noTimes: false
paginate: 10
paginatePath: “page”
permalinks:
pluralizeListTitles: true
preserveTaxonomyNames: false
publishDir: “public”
pygmentsCodeFencesGuessSyntax: false
pygmentsStyle: “monokai”
pygmentsUseClasses: false
rssLimit: 15
SectionPagesMenu: “”
sitemap:
source: “”
staticDir: “static”
stepAnalysis: false
themesDir: “themes”
theme: “”
title: “”
uglyURLs: false
verbose: false
verboseLog: false
watch: true
taxonomies:
{{< /code >}}
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 = "https://yoursite.example.com/"
canonifyURLs = true
title = "My Hugo Site"
[taxonomies]
category = "categories"
tag = "tags"
[params]
subtitle = "Hugo is Absurdly Fast!"
author = "John Doe"
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”
baseURL = “”
buildDrafts = false
buildFuture = false
buildExpired = false
relativeURLs = false
canonifyURLs = false
config = “config.toml”
contentDir = “content”
dataDir = “data”
defaultExtension = “html”
defaultLayout = “post”
defaultContentLanguage = “en”
defaultContentLanguageInSubdir = false
disableLiveReload = false
disableRSS = false
disableSitemap = false
enableGitInfo = false
enableRobotsTXT = false
disable404 = false
disableHugoGeneratorInject = false
disableKinds = []
disablePathToLower = false
enableEmoji = false
enableMissingTranslationPlaceholders = false
footnoteAnchorPrefix = “”
footnoteReturnLinkContents = “”
googleAnalytics = “”
hasCJKLanguage = false
languageCode = “”
layoutDir = “layouts”
log = false
logFile =
rssLimit = 15
metaDataFormat = “toml”
newContentEditor = “”
noChmod = false
noTimes = false
paginate = 10
paginatePath = “page”
permalinks =
pluralizeListTitles = true
preserveTaxonomyNames = false
publishDir = “public”
pygmentsCodeFencesGuessSyntax = false
pygmentsStyle = “monokai”
pygmentsUseClasses = false
SectionPagesMenu =
sitemap =
source = “”
staticDir = “static”
stepAnalysis = false
themesDir = “themes”
theme = “”
title = “”
uglyURLs = false
verbose = false
verboseLog = false
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:
~/sites/yourhugosite
hugo config | grep emoji
enableemoji: true
{{% /note %}}
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 %}}
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.
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/bfconfig.md” markdown=“true” >}}
{{% note %}}
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.{{< 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 >}}
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.
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.
{{% 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 %}}
The community-contributed themes featured on themes.gohugo.io are hosted in a [centralized GitHub repository][themesrepo]. The Hugo Themes Repo at https://github.com/gohugoio/hugoThemes 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 %}}
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 https://github.com/gohugoio/hugoThemes.git 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.
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 https://github.com/spf13/hyde:
{{< code file=“clone-theme.sh” >}}
cd themes
git clone https://github.com/spf13/hyde
{{< /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 README.md
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 %}}
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.
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.
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
FileIf 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 %}}
[themesrepo]: https://github.com/gohugoio/hugoThemes
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 %}}
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:
/themes/<THEME>/static/js/jquery.min.js
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:
/static/js/jquery.min.js
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:
/themes/<THEME>/layouts/_default/single.html
Would be overwritten by
/layouts/_default/single.html
{{% 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 %}}
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/default.md
or /layouts/_default/*.html
, respectively), it will override the file of the same name in the corresponding theme directory (i.e., themes/<THEME>/archetypes/default.md
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/
{{% 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]
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.
The default single file layout is located at layouts/_default/single.html
.
The default list file layout is located at layouts/_default/list.html
.
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:
/css
/js
/img
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.
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.
{{% note %}}
This section is not updated with the new nested sections support in Hugo 0.24, see https://github.com/gohugoio/hugoDocs/issues/36
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
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
| └── _index.md // <- http://example.com/about/
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost/
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness/
| └── secondpost.md // <- http://example.com/post/secondpost/
└── quote
├── first.md // <- http://example.com/quote/first/
└── second.md // <- http://example.com/quote/second/
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 = "http://example.com"
in your site’s configuration file.
_index.md
_index.md
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 _index.md
using the .Site.GetPage
function.
You can keep one _index.md
for your homepage and one in each of your content sections, taxonomies, and taxonomy terms. The following shows typical placement of an _index.md
that would contain content and front matter for a posts
section list page on a Hugo website:
. url
. ⊢--^-⊣
. path slug
. ⊢--^-⊣⊢---^---⊣
. filepath
. ⊢------^------⊣
content/posts/_index.md
At build, this will output to the following destination with the associated values:
url ("/posts/")
⊢-^-⊣
baseurl section ("posts")
⊢--------^---------⊣⊢-^-⊣
permalink
⊢----------^-------------⊣
http://example.com/posts/index.html
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/my-first-hugo-post.md")
. ⊢-----------^------------⊣
. section slug
. ⊢-^-⊣⊢--------^----------⊣
content/posts/my-first-hugo-post.md
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
⊢--------^--------⊣⊢-^--⊣⊢-------^---------⊣
permalink
⊢--------------------^---------------------⊣
http://example.com/posts/my-first-hugo-post/index.html
To continue the example, the following demonstrates destination paths for a file located at content/events/chicago/lollapalooza.md
in the same site:
section
⊢--^--⊣
url
⊢-------------^------------⊣
baseURL path slug
⊢--------^--------⊣ ⊢------^-----⊣⊢----^------⊣
permalink
⊢----------------------^-----------------------⊣
http://example.com/events/chicago/lollapalooza/
{{% 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 lollapalooza.md
is events
and not chicago
. See the related issue on GitHub.
{{% /note %}}
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.
section
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.
slug
A content’s slug
is either name.extension
or name/
. The value for slug
is determined by
lollapalooza.md
) ORpath
A content’s path
is determined by the section’s path to the file. The file path
url
The url
is the relative URL for the piece of content. The url
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:
filename
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/my-post.md
becomes example.com/posts/my-post/
).
slug
When defined in the front matter, the slug
can take the place of the filename for the destination.
{{< /code >}}
This will render to the following destination according to Hugo’s default behavior:
example.com/posts/new-post/
section
section
is determined by a content’s location on disk and cannot be specified in the front matter. See sections for more information.
type
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 >}}
url
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 >}}
Assuming your baseURL
is configured to https://example.com
, the addition of url
to the front matter will make old-url.md
render to the following destination:
https://example.com/blog/new-url/
You can see more information on how to control output paths in URL Management.
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 %}}
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/bfconfig.md” markdown=“true” >}}
Hugo provides some convenient methods for extending markdown.
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.
{{< code file=“content/my-to-do-list.md” >}}
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>
</ul>
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.
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.
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.
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 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.
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 (cdn.js.com):
{{< code file=“add-mathjax-to-page.html” >}}
{{< /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.
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.
{{% 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 README.md
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” >}}
{{< /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!
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 %}}
Markdown syntax is simple enough to learn in a single sitting. The following are excellent resources to get you up and running:
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.
Hugo supports three formats for front matter, each with their own identifying tokens.
+++
.---
.{
’ and ‘}
’, followed by a new line.+++
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 = [
"Development",
"VIM"
]
slug = "spf13-vim-3-0-release-and-new-website"
+++
---
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"
categories:
- "Development"
- "VIM"
slug: "spf13-vim-3-0-release-and-new-website"
---
{
"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": [
"Development",
"VIM"
],
"slug": "spf13-vim-3-0-release-and-new-website"
}
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
date
description
draft
true
, the content will not be rendered unless the --buildDrafts
flag is passed to the hugo
command.expiryDate
--buildExpired
flag is passed to the hugo
command.isCJKLanguage
true
, Hugo will explicitly treat the content as a CJK language; both .Summary
and .WordCount
work properly in CJK languages.keywords
layout
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
linkTitle
linktitle
before the title
. Hugo can also order lists of content by linktitle
.markup
"rst"
for reStructuredText (requiresrst2html
) or "md"
(default) for Markdown.outputs
publishDate
--buildFuture
flag is passed to hugo
.slug
taxonomies
tags
and categories
in the above front matter examples.title
type
url
weight
{{% 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.
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.
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.
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.
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.
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 */%}}
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 */>}}
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.
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
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
figure
Input{{< code file=“figure-input-example.md” >}}
{{</* figure src=“/media/spf13.jpg” title=“Steve Francia” */>}}
{{< /code >}}
figure
Output{{< output file=“figure-output-example.html” >}}
{{< /output >}}gist
Bloggers often want to include GitHub gists when writing posts. Let’s suppose we want to use the gist at the following url:
https://gist.github.com/spf13/7896402
We can embed the gist in our content via username and gist ID pulled from the URL:
{{</* gist spf13 7896402 */>}}
gist
InputIf 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-input.md” >}}
{{</* gist spf13 7896402 “img.html” */>}}
{{< /code >}}
gist
Output{{< output file=“gist-output.html” >}}
{{< gist spf13 7896402 >}}
{{< /output >}}
gist
DisplayTo 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 >}}
highlight
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.
highlight
Input{{< code file=“content/tutorials/learn-html.md” >}}
{{</* highlight html */>}}
highlight
OutputThe 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 %}}
instagram
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:
https://www.instagram.com/p/BWNjjyYFxVx/
instagram
Input{{< code file=“instagram-input.md” >}}
{{</* instagram BWNjjyYFxVx */>}}
{{< /code >}}
You also have the option to hide the caption:
{{< code file=“instagram-input-hide-caption.md” >}}
{{</* instagram BWNjjyYFxVx hidecaption */>}}
{{< /code >}}
instagram
OutputBy 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 >}}
instagram
DisplayUsing 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/post.md
) or their logical name (post.md
) 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
.
ref
and relref
Input[Neat]({{</* ref "blog/neat.md" */>}})
[Who]({{</* relref "about.md#who" */>}})
ref
and relref
OutputAssuming that standard Hugo pretty URLs are turned on.
<a href="/blog/neat">Neat</a>
<a href="/about/#who:c28654c202e73453784cfd2c5ab356c0">Who</a>
speakerdeck
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="//speakerdeck.com/assets/embed.js"></script>
speakerdeck
Example InputExtract the value from the field data-id
and pass it to the shortcode:
{{< code file=“speakerdeck-example-input.md” >}}
{{</* speakerdeck 4e8126e72d853c0060001f97 */>}}
{{< /code >}}
speakerdeck
Example Output{{< output file=“speakerdeck-example-input.md” >}}
{{< speakerdeck 4e8126e72d853c0060001f97 >}}
{{< /output >}}
speakerdeck
Example DisplayFor 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 >}}
tweet
You want to include a single tweet into your blog post? Everything you need is the URL of the tweet:
https://twitter.com/spf13/status/877500564405444608
tweet
InputPass the tweet’s ID from the URL as a parameter to the tweet
shortcode:
{{< code file=“example-tweet-input.md” >}}
{{</* tweet 877500564405444608 */>}}
{{< /code >}}
tweet
OutputUsing 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 >}}
tweet
DisplayUsing 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 >}}
vimeo
Adding a video from Vimeo is equivalent to the YouTube shortcode above.
https://vimeo.com/channels/staffpicks/146022717
vimeo
InputExtract the ID from the video’s URL and pass it to the vimeo
shortcode:
{{< code file=“example-vimeo-input.md” >}}
{{</* vimeo 146022717 */>}}
{{< /code >}}
vimeo
OutputUsing 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 %}}
vimeo
DisplayUsing 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 >}}
youtube
The youtube
shortcode embeds a responsive video player for YouTube videos. Only the ID of the video is required, e.g.:
https://www.youtube.com/watch?v=w7Ft2ymGmfc
youtube
InputCopy the YouTube video ID that follows v=
in the video’s URL and pass it to the youtube
shortcode:
{{< code file=“example-youtube-input.md” >}}
{{</* 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=“example-youtube-input-with-autoplay.md” >}}
{{</* youtube id=“w7Ft2ymGmfc” autoplay=“true” */>}}
{{< /code >}}
youtube
OutputUsing 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 >}}
youtube
DisplayUsing 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 >}}
To learn more about creating custom shortcodes, see the shortcode template documentation.
{{% note %}}
This section is not updated with the new nested sections support in Hugo 0.24, see https://github.com/gohugoio/hugoDocs/issues/36
{{% /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
| ├── _index.md // <- example.com/authors/
| ├── john-doe.md // <- example.com/authors/john-doe/
| └── jane-doe.md // <- example.com/authors/jane-doe/
└── events
| ├── _index.md // <- example.com/events/
| ├── event-1.md // <- example.com/events/event-1/
| ├── event-2.md // <- example.com/events/event-2/
| └── event-3.md // <- example.com/events/event-3/
└── posts
| ├── _index.md // <- example.com/posts/
| ├── event-1.md // <- example.com/posts/event-1/
| ├── event-2.md // <- example.com/posts/event-2/
| ├── event-3.md // <- example.com/posts/event-3/
| ├── event-4.md // <- example.com/posts/event-4/
| └── event-5.md // <- example.com/posts/event-5/
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 _index.md
in order for Hugo to correctly render the front matter and content.
{{% warning “index.md
vs _index.md
” %}}
Hugo themes developed before v0.18 often used an index.md
(i.e., without the leading underscore [_
]) in a content section as a hack to emulate the behavior of _index.md
. 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 _index.md
as content for your section index pages. Note: _index.md
’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 _index.md
, configure disableKinds
accordingly in your site’s configuration.
{{% /warning %}}
By default, everything created within a section will use the content type that matches the section name. For example, Hugo will assume that posts/post-1.md
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/posts.md
.
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.
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.
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 = “[email protected]”
weight = 10
[social]
facebook = “alice.allison”
twitter = “alice”
googleplus = “aliceallison1”
website = “www.example.com”
[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.
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.
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 %}}
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 }}
{{ .ShortBio }}
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:
taxonomies:
author: authors
[taxonomies]
author = "authors"
In the next step we can create a template to list all authors of your website. Later, the list can be accessed at www.example.com/authors/
. 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” >}}
.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.
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 www.example.com/authors/<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 }}
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.
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.
[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.
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/new-post.md
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
”.
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.
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/my-first-event.md” 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/ my-first-event.md
is of type event
and should render using the birthday
layout.
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 _index.md
in content directories to add both content and front matter to list pages. However, type
and layout
declared in the front matter of _index.md
are not currently respected at build time as of v0.19. This is a known issue (#3005).
{{% /warning %}}
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.
The lookup order for the content/events/my-first-event.md
templates would be as follows:
layouts/event/birthday.html
layouts/event/single.html
layouts/events/single.html
layouts/_default/single.html
We can then create a custom archetype with preconfigured front matter at event.md
in the /archetypes
directory; i.e. archetypes/event.md
.
Read Archetypes for more information on archetype usage with hugo new
.
[Tumblr]: https://www.tumblr.com/
{{% note %}}
This section is outdated, see https://github.com/gohugoio/hugoDocs/issues/11
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
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>/<file-name.md>
We can use this pattern to create a new .md
file in the posts
section:
{{< code file=“archetype-example.sh” >}}
hugo new posts/my-first-post.md
{{< /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/my-first-post.md” >}}
+++
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/my-first-post.md
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.draft = true
, is not inherited by your default or custom archetypes but is included in Hugo’s automatically scaffolded default.md
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.
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/my-first-post.md
in the following order:
archetypes/posts.md
archetypes/default.md
themes/<THEME>/archetypes/posts.md
themes/<THEME>/archetypes/default.md
(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 %}}
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 are convenient if your content’s front matter stays consistent across multiple content sections.
When you create a new Hugo project using hugo new site
, you’ll notice that Hugo has already scaffolded a file at archetypes/default.md
.
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 default.md
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/default.md” >}}
+++
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 %}}
With an archetypes/default.md
in place, we can use the CLI to create a new post in the posts
content section:
{{< code file=“new-post-from-default.sh” >}}
$ hugo new posts/my-new-post.md
{{< /code >}}
Hugo then creates a new markdown file with the following front matter:
{{< output file=“content/posts/my-new-post.md” >}}
+++
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/default.md
.
{{% 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 %}}
Suppose your site’s posts
section requires more sophisticated front matter than what has been specified in archetypes/default.md
. You can create a custom archetype for your posts at archetypes/posts.md
that includes the full set of front matter to be added to the two default archetypes fields.
{{< code file=“archetypes/posts.md”>}}
+++
description = “”
tags = “”
categories = “”
+++
{{< /code >}}
With an archetypes/posts.md
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=“new-post-from-custom.sh” >}}
$ hugo new posts/post-from-custom.md
{{< /code >}}
This time, Hugo recognizes our custom archetypes/posts.md
archetype and uses it instead of archetypes/default.md
. 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/post-from-custom-archetype.md” >}}
+++
categories = “”
date = 2017-02-13T17:24:43-08:00
description = “”
tags = “”
title = “post from custom archetype”
+++
{{< /output >}}
As an example of archetypes in practice, the following is the functions
archetype from the Hugo docs:
{{< code file=“archetypes/functions.md” >}}
{{< readfile file=“/themes/gohugoioTheme/archetypes/functions.md” >}}
{{< /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 %}}
Hugo includes support for user-defined groupings of content called taxonomies. Taxonomies are classifications of logical relationships between content.
{{< youtube “-np9GX6cL38” >}}
Let’s assume you are making a website about movies. You may want to include the following taxonomies:
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.
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 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"]
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:
example.com/categories/
that lists all the terms within the taxonomy/categories/development/
) for each of the terms that shows a listing of all pages marked as part of that taxonomy within any content file’s front matterTaxonomies 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.
[taxonomies]
tag = "tags"
category = "categories"
series = "series"
taxonomies:
tag: "tags"
category: "categories"
series: "series"
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 _index.md
for this purpose.
Note also that taxonomy permalinks are not configurable.
{{% /note %}}
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 %}}
+++
title = "Hugo: A fast and flexible static site generator"
tags = [ "Development", "Go", "fast", "Blogging" ]
categories = [ "Development" ]
series = [ "Go Web Dev" ]
slug = "hugo"
project_url = "https://github.com/gohugoio/hugo"
+++
---
title: "Hugo: A fast and flexible static site generator"
#tags: ["Development", "Go", "fast", "Blogging"]
categories: ["Development"]
series: ["Go Web Dev"]
slug: "hugo"
project_url: "https://github.com/gohugoio/hugo"
---
{
"title": "Hugo: A fast and flexible static site generator",
"tags": [
"Development",
"Go",
"fast",
"Blogging"
],
"categories" : [
"Development"
],
"series" : [
"Go Web Dev"
],
"slug": "hugo",
"project_url": "https://github.com/gohugoio/hugo"
}
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.
weight
+++
title = "foo"
tags = [ "a", "b", "c" ]
tags_weight = 22
categories = ["d"]
categories_weight = 44
+++
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 %}}
With the use of the .Summary
page variable, Hugo generates summaries of content to use as a short version in summary views.
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.
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:
{{% 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 %}}
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 %}}
<!--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 %}}
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 }}
{{ 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/
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 (http://1.com/about/
) or relative (/about/
), respectively.
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., about.md
) with or without an appended in-document anchor
(#who
) without spaces.
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/post.md
, either format will produce the same result:
{{</* relref "blog/post.md" */>}} => `/blog/post/`
{{</* relref "post.md" */>}} => `/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
│ └── my-birthday.md
├── galleries
│ └── my-birthday.md
├── meta
│ └── my-article.md
└── posts
└── my-birthday.md
To be sure to get the correct reference in this case, use the full path:
{{< code file=“content/meta/my-article.md” copy=“false” >}}
{{</* relref “events/my-birthday.md” */>}} => /events/my-birthday/
{{< /code >}}
{{< todo >}}Remove this warning when https://github.com/gohugoio/hugo/issues/3703 is released.{{< /todo >}}
A relative document name must not begin with a slash (/
).
{{</* relref "/events/my-birthday.md" */>}} => ""
If the page exists in multiple output formats, ref
or relref
can be used with a output format name:
[Neat]({{</* ref "blog/neat.md" "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/hugo-features.md#content" */>}} => /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/post.md#who" */>}} => /blog/post/#who:badcafe
More information about document unique identifiers and headings can be found [below]({{< ref “#hugo-heading-anchors” >}}).
{{</* ref "blog/post.md" */>}}
=> http://example.com/blog/post/
{{</* ref "post.md#tldr" */>}}
=> http://example.com/blog/post/#tldr:caffebad
{{</* relref "post.md" */>}}
=> /blog/post/
{{</* relref "blog/post.md#tldr" */>}}
=> /blog/post/#tldr:caffebad
{{</* ref "#tldr" */>}}
=> #tldr:badcaffe
{{</* relref "#tldr" */>}}
=> #tldr:badcaffe
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/post.md
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/cross-references.md#hugo-heading-anchors" */>}}
/content-management/cross-references/#hugo-heading-anchors:77cd9ea530577debf4ce0f28c8dca242
[shortcode]: /content-management/shortcodes/
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.
{{< code file=“config.yml” copy=“false” >}}
permalinks:
post: /:year/:month/:title/
{{< /code >}}
{{< 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/sample-entry.md
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 http://example.com/2013/11/sample-entry/
.
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
:month
:monthname
:day
:weekday
:weekdayname
:yearday
:section
:title
:slug
:filename
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.
Let’s assume you create a new piece of content at content/posts/my-awesome-blog-post.md
. The content is a revision of your previous post at content/posts/my-original-url.md
. You can create an aliases
field in the front matter of your new my-awesome-blog-post.md
where you can add previous paths. The following examples show how to create this filed in TOML and YAML front matter, respectively.
{{< code file=“content/posts/my-awesome-post.md” copy=“false” >}}
+++
aliases = [
“/posts/my-original-url/”,
“/2010/01/01/even-earlier-url.html”
]
+++
{{< /code >}}
{{< /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 example.com/posts/my-original-url/
will be immediately redirected to example.com/posts/my-awesome-blog-post/
.
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/my-new-post.es.md
:
---
aliases:
- /es/posts/my-original-post/
---
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/my-intended-url.md
with the following in the front matter:
---
title: My New post
aliases: [/posts/my-old-url/]
---
Assuming a baseURL
of example.com
, the contents of the auto-generated alias .html
found at https://example.com/posts/my-old-url/ will contain the following:
<!DOCTYPE html>
<html>
<head>
<title>http://example.com/posts/my-intended-url</title>
<link rel="canonical" href="http://example.com/posts/my-intended-url"/>
<meta name=\"robots\" content=\"noindex\">
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta http-equiv="refresh" content="0; url=http://example.com/posts/my-intended-url"/>
</head>
</html>
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 https://example.com/posts/my-old-url
, 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
Page
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:
content/posts/_index.md
=> example.com/posts/index.html
content/posts/post-1.md
=> example.com/posts/post-1/
If you would like to have what are often referred to as “ugly URLs” (e.g., example.com/urls.html), 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
| └── _index.md // <- http://example.com/about/
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost/
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness/
| └── secondpost.md // <- http://example.com/post/secondpost/
└── quote
├── first.md // <- http://example.com/quote/first/
└── second.md // <- http://example.com/quote/second/
Here’s the same organization run with hugo --uglyURLs
:
.
└── content
└── about
| └── _index.md // <- http://example.com/about/index.html
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost.html
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness.html
| └── secondpost.md // <- http://example.com/post/secondpost.html
└── quote
├── first.md // <- http://example.com/quote/first.html
└── second.md // <- http://example.com/quote/second.html
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 = https://example.com/
, the relative URL /css/foo.css
would be turned into the absolute URL http://example.com/css/foo.css
.
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
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.
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:
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
.Name
.Menu
.Identifier
.Pre
.Post
.Weight
.Parent
.Children
Note that menus also have the following functions available as well:
.HasChildren
Additionally, there are some relevant functions available to menus on a page:
.IsMenuCurrent
.HasMenuCurrent
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.
---
menu: "main"
---
---
menu: ["main", "footer"]
---
---
menu:
docs:
parent: 'extras'
weight: 20
---
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 >}}
{{% note %}}
The URLs must be relative to the context root. If the baseURL
is http://example.com/mysite/
, 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 http://subdomain.example.com/
, the output will be http://subdomain.example.com
.
{{% /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.
See Menu Templates for information on how to render your site menus within your templates.
{{% 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.’
The following is an example of a very basic single page template:
{{< code file=“layout/_default/single.html” download=“single.html” >}}
{{ define “main” }}
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”) }}
{{% 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.
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.
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
See Partial Templates to learn how to add the Disqus partial to your Hugo website’s templates.
There are a few alternatives to commenting on static sites for those who do not want to use Disqus:
You should define the available languages in a Languages
section in your site configuration.
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”
[Languages.fr]
copyright = “Tout est à moi”
title = “Mon blog”
weight = 2
[Languages.fr.params]
linkedin = “lien-francais”
[Languages.fr.navigation]
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 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”
[Languages.en.blackfriday]
angledQuotes = false
[Languages.fr]
weight = 2
title = “Français”
[Languages.fr.Taxonomies]
plaque = “plaques”
{{< /code >}}
Translated articles are identified by the name of the content file.
/content/about.en.md
/content/about.fr.md
In this example, the about.md
will be assigned the configured defaultContentLanguage
.
/content/about.md
/content/about.fr.md
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/about.fr.md
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 https://github.com/gohugoio/hugo/issues/2699
{{% /note %}}
{{< todo >}}Rewrite/remove the above one issue is fixed.{{< /todo >}}
To create a list of links to translated content, use a template similar to the following:
{{< code file=“layouts/partials/i18nlist.html” >}}
{{ if .IsTranslated }}
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.
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
:
[home]
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
:
[wordCount]
other = "This article has {{ .WordCount }} words."
An example of singular and plural form:
[readingTime]
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
i18n|MISSING_TRANSLATION|en|wordCount
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 }})
</time>
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"
[languages.en]
weight = 0
languageName = "English"
[[languages.en.menu.main]]
url = "/"
name = "Home"
weight = 0
[languages.de]
weight = 10
languageName = "Deutsch"
[[languages.de.menu.main]]
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.
<ul>
{{- $currentPage := . -}}
{{ range .Site.Menus.main -}}
<li class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}">
<a href="{{ .URL | absLangURL }}">{{ .Name }}</a>
</li>
{{- end }}
</ul>
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 %}}
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:
.Permalink
or .URL
relLangURL
template function or the absLangURL
template function OR{{ .LanguagePrefix }}
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.
{{% 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.
Golang templates are HTML files with the addition of variables and functions. Golang template variables and functions are accessible within {{ }}
.
{{ foo }}
Parameters for functions are separated using spaces. The following example calls the add
function with inputs of 1
and 2
:
{{ add 1 2 }}
Accessing the Page Parameter bar
defined in a piece of content’s front matter.
{{ .Params.bar }}
{{ 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 https://github.com/golang/go/issues/10608.
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.
{{ add 1 2 }}
=> 3
{{ 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 "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.
{{ range array }}
{{ . }}
{{ end }}
{{range $element := array}}
{{ $element }}
{{ end }}
{{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:
if
{{ if isset .Params "title" }}<h4>{{ index .Params "title" }}</h4>{{ end }}
if
… else
{{ if isset .Params "alt" }}
{{ index .Params "alt" }}
{{else}}
{{ index .Params "caption" }}
{{ end }}
and
& or
{{ if and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}}
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 }}
if
… else 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.
shuffle
The following two examples are functionally the same:
{{ shuffle (seq 1 5) }}
{{ (seq 1 5) | shuffle }}
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 }}
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 }}
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 }}
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:
The following shows how to define a variable independent of the context.
{{< code file=“tags-range-with-page-variable.html” >}}
{{ $title := .Site.Title }}
{{% 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 %}}
$.
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” >}}
{{% 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:
<div>
{{ .Title }}
</div>
Which will output:
<div>
Hello, World!
</div>
Leveraging the -
in the following example will remove the extra white space surrounding the .Title
variable and remove the newline:
<div>
{{- .Title -}}
</div>
Which then outputs:
<div>Hello, World!</div>
Go considers the following characters whitespace:
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.
Page
) ParametersYou 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 }}
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
.
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>
</footer>{{end}}
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}}
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.
<nav>
<h1>Recent Posts</h1>
<ul>
{{- range first .Site.Params.SidebarRecentLimit .Site.Pages -}}
<li><a href="{{.RelPermalink}}">{{.Title}}</a></li>
{{- end -}}
</ul>
</nav>
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” >}}
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 %}}
The respective lookup order for each of Hugo’s templates has been defined throughout the Hugo docs:
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.
mytheme
(specified in the project’s configuration)..
├── content
│ ├── events
│ │ ├── _index.md
│ │ └── my-first-event.md
│ └── posts
│ ├── my-first-post.md
│ └── my-second-post.md
├── 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 (i.e..md
) files.
{{% note %}}
Only three of the four markdown files in the above project are subject to the single page lookup order. _index.md
is a specific kind
in Hugo. Whereas my-first-post.md
, my-second-post.md
, and my-first-event.md
are all of kind page
, all _index.md
files in a Hugo project are used to add content and front matter to list pages. In this example, events/_index.md
will render according to its section template and respective lookup order.
{{% /note %}}
my-first-post.md
{{< /code >}}
When building your site, Hugo will go through the lookup order until it finds what it needs for my-first-post.md
:
/layouts/UNSPECIFIED/UNSPECIFIED.html
/layouts/posts/UNSPECIFIED.html
/layouts/UNSPECIFIED/single.html
/layouts/posts/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
/themes/<THEME>/layouts/posts/UNSPECIFIED.html
/themes/<THEME>/layouts/UNSPECIFIED/single.html
/themes/<THEME>/layouts/posts/single.html
/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. my-first-post.md
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.)
my-first-post.md
also does not specify a layout
in its front matter. Therefore, Hugo assumes that my-first-post.md
, 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).
my-second-post.md
{{< /code >}}
Here is the way Hugo traverses the single-page lookup order for my-second-post.md
:
/layouts/review/reviewarticle.html
/layouts/posts/reviewarticle.html
/layouts/review/single.html
/layouts/posts/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/review/reviewarticle.html
/themes/<THEME>/layouts/posts/reviewarticle.html
/themes/<THEME>/layouts/review/single.html
/themes/<THEME>/layouts/posts/single.html
/themes/<THEME>/layouts/_default/single.html
The front matter in my-second-post.md
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 my-second-post.md
is review
and not reviews
. This is because type is always singular when defined in front matter.
{{% /note%}}
my-first-event.md
{{< /code >}}
Here is the way Hugo traverses the single-page lookup order for my-first-event.md
:
/layouts/UNSPECIFIED/UNSPECIFIED.html
/layouts/events/UNSPECIFIED.html
/layouts/UNSPECIFIED/single.html
/layouts/events/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
/themes/<THEME>/layouts/events/UNSPECIFIED.html
/themes/<THEME>/layouts/UNSPECIFIED/single.html
/themes/<THEME>/layouts/events/single.html
/themes/<THEME>/layouts/_default/single.html
{{% note %}}
my-first-event.md
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 %}}
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.
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” >}}
Note:
text/html
to asp
.Suffix
is the value that will be used for URLs and filenames for that media type in Hugo.Type
is the identifier that must be used when defining new/custom Output Formats
(see below).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
:
[mediaTypes]
[mediaTypes."text/enriched"]
suffix = "enr"
[mediaTypes."text/html"]
suffix = "asp"
The above example adds one new media type, text/enriched
, and changes the suffix for the built-in text/html
media type.
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”>}}
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
.MediaType
must match the Type
of an already defined media type.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.
[outputFormats.MyEnrichedFormat]
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
http://example.org
, it will produce a plain text homepage with the URL bep://example.org/myindex.enr
.
The following is the full list of configuration options for output formats and their default values:
name
mediaType
Type
of a defined media type.path
baseName
index
.rel
rel
values in link
tags. Default: alternate
.protocol
baseURL
for this output format.isPlainText
false
.isHTML
HTML
-type formats; e.g., page aliases.noUgly
uglyURLs
is set to true
in your site. Default: false
.notAlternative
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
.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
:
[outputs]
home = ["HTML", "AMP", "RSS"]
page = ["HTML"]
Example from site config.yml
:
outputs:
home: ["HTML", "AMP", "RSS"]
page: ["HTML"]
Page
Kind
(i.e, page
, home
, section
, taxonomy
, or taxonomyTerm
).Name
of a defined Output Format
.Kind
without a definition will default to HTML
.Page
in the front matter of content files.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"
outputs:
- html
- amp
- json
---
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/neat.md" "amp" */>}})
[Who]({{</* relref "about.md#who" "amp" */>}})
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" . }}
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.
The lookup order for base templates is as follows:
/layouts/section/<TYPE>-baseof.html
/themes/<THEME>/layouts/section/<TYPE>-baseof.html
/layouts/<TYPE>/baseof.html
/themes/<THEME>/layouts/<TYPE>/baseof.html
/layouts/section/baseof.html
/themes/<THEME>/layouts/section/baseof.html
/layouts/_default/post-baseof.html
/themes/<THEME>/layouts/_default/post-baseof.html
/layouts/_default/baseof.html
/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.
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:
/layouts/section/post-baseof.html
/themes/mytheme/layouts/section/post-baseof.html
/layouts/post/baseof.html
/themes/mytheme/layouts/post/baseof.html
/layouts/section/baseof.html
/themes/mytheme/layouts/section/baseof.html
/layouts/_default/post-baseof.html
/themes/mytheme/layouts/_default/post-baseof.html
/layouts/_default/baseof.html
/themes/mytheme/layouts/_default/baseof.html
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” >}}
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” }}
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” }}
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:
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
:
layouts/_default/section.html
layouts/_default/list.html
layouts/_default/taxonomy.html
themes/<THEME>/layouts/_default/taxonomy.html
Since v0.18, everything in Hugo is a Page
. This means list pages and the homepage can have associated content files (i.e. _index.md
) 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 _index.md
content files will render according to a list template and not according to a single page template.
{{% /note %}}
The following is an example of a typical Hugo project directory’s content:
.
...
├── content
| ├── post
| | ├── _index.md
| | ├── post-01.md
| | └── post-02.md
| └── quote
| | ├── quote-01.md
| | └── quote-02.md
...
Using the above example, let’s assume you have the following in content/post/_index.md
:
I decided to start learning Golang in March 2017.
Follow my journey through this new blog.
{{< /code >}}
You can now access this _index.md
’s’ content in your list template:
{{< code file=“layouts/_default/list.html” download=“list.html” >}}
{{ define “main” }}
This above will output the following HTML:
{{< code file=“example.com/post/index.html” copy=“false” >}}
I decided to start learning Golang in March 2017.
Follow my journey through this new blog.
_index.md
You do not have to create an _index.md
file for every list page (i.e. section, taxonomy, taxonomy terms, etc) or the homepage. If Hugo does not find an _index.md
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 _index.md
file to pull from:
{{< code file=“example.com/quote/index.html” copy=“false” >}}
{{% 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 %}}
This list template has been modified slightly from a template originally used in spf13.com. 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” . }}
{{< code file=“layouts/_default/taxonomies.html” download=“taxonomies.html” >}}
{{ define “main” }}
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:
{{< code file=“layouts/partials/default-order.html” >}}
{{< code file=“layouts/partials/by-weight.html” >}}
{{< code file=“layouts/partials/by-date.html” >}}
{{< code file=“layouts/partials/by-publish-date.html” >}}
{{< code file=“layouts/partials/by-expiry-date.html” >}}
{{< code file=“layouts/partials/by-last-mod.html” >}}
{{< code file=“layouts/partials/by-length.html” >}}
{{< code file=“layouts/partials/by-title.html” >}}
{{< code file=“layouts/partials/by-link-title.html” >}}
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 >}}
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” >}}
Hugo provides some functions for grouping pages by Section, Type, Date, etc.
{{< code file=“layouts/partials/by-page-field.html” >}}
{{ range .Data.Pages.GroupBy “Section” }}
In the above example, you may want {{.Title}}
to point the title
field you have added to your _index.md
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 }}
{{< code file=“layouts/partials/by-page-date.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” }}
{{< code file=“layouts/partials/by-page-publish-date.html” >}}
{{ range .Data.Pages.GroupByPublishDate “2006-01” }}
{{< code file=“layouts/partials/by-page-param.html” >}}
{{ range .Data.Pages.GroupByParam “param_key” }}
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” }}
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.
{{ range (.Data.Pages.GroupBy "Section").Reverse }}
{{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}
{{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
{{ range .Data.Pages.GroupBy "Section" "desc" }}
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:
date
field in front matter.title
.{{< code file=“layouts/partials/by-group-by-page.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” “asc” }}
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
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:
array
or slice of maps or structs
key
or field name
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
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:
array
or slice of maps or structs
number of elements
{{< code file=“layout/_default/section.html” >}}
{{ range first 10 .Data.Pages }}
{{ .Render “summary” }}
{{ end }}
{{< /code >}}
first
and where
TogetherUsing 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 >}}
In Hugo, A list template is any template that will be used to render multiple pieces of content in a single HTML page.
This list template is used for spf13.com. 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” . }}
{{< code file=“layouts/_default/taxonomies.html” download=“taxonomies.html” >}}
{{ define “main” }}
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:
{{< code file=“layouts/partials/order-default.html” >}}
{{< code file=“layouts/partials/by-weight.html” >}}
{{ range .Data.Pages.ByWeight }}
{{< code file=“layouts/partials/by-date.html” >}}
{{ range .Data.Pages.ByDate }}
{{< code file=“layouts/partials/by-publish-date.html” >}}
{{ range .Data.Pages.ByPublishDate }}
{{< code file=“layouts/partials/by-expiry-date.html” >}}
{{ range .Data.Pages.ByExpiryDate }}
{{< code file=“layouts/partials/by-last-mod.html” >}}
{{ range .Data.Pages.ByLastmod }}
{{< code file=“layouts/partials/by-length.html” >}}
{{ range .Data.Pages.ByLength }}
{{< code file=“layouts/partials/by-title.html” >}}
{{ range .Data.Pages.ByTitle }}
{{< code file=“layouts/partials/by-link-title.html” >}}
{{ range .Data.Pages.ByLinkTitle }}
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 >}}
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 }}
Hugo provides some functions for grouping pages by Section, Type, Date, etc.
{{< code file=“layouts/partials/by-page-field.html” >}}
{{ range .Data.Pages.GroupBy “Section” }}
{{< code file=“layouts/partials/by-page-date.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” }}
{{< code file=“layouts/partials/by-page-publish-date.html” >}}
{{ range .Data.Pages.GroupByPublishDate “2006-01” }}
{{< code file=“layouts/partials/by-page-param.html” >}}
{{ range .Data.Pages.GroupByParam “param_key” }}
{{< code file=“layouts/partials/by-page-param-as-date.html” >}}
{{ range .Data.Pages.GroupByParamDate “param_key” “2006-01” }}
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.
{{ range (.Data.Pages.GroupBy "Section").Reverse }}
{{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}
{{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
{{ range .Data.Pages.GroupBy "Section" "desc" }}
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” }}
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
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:
array
or a slice of maps or structs
key
or field name
match value
{{< code file=“layouts/_default/.html” >}}
{{ range where .Data.Pages “Section” “post” }}
{{ .Content }}
{{ end }}
{{< /code >}}
first
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:
array
or slice of maps or structs
number of elements
{{< code file=“layout/_default/section.html” >}}
{{ range first 10 .Data.Pages }}
{{ .Render “summary” }}
{{ end }}
{{< /code >}}
first
and where
TogetherUsing 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 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 %}}
The lookup order for the homepage template is as follows:
/layouts/index.html
/layouts/_default/list.html
/themes/<THEME>/layouts/index.html
/themes/<THEME>/layouts/_default/list.html
The homepage, similar to other list pages in Hugo, accepts content and front matter from an _index.md
file. This file should live at the root of your content
folder (i.e., content/_index.md
). 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 _index.md
in adding content and front matter to list pages.
.Data.Pages
on the HomepageIn addition to the standard page variables, the homepage template has access to all site content via .Data.Pages
.
The following is an example of a homepage template that uses partial, base templates, and a content file at content/_index.md
to populate the {{.Title}}
and {{Content}}
page variables.
{{< code file=“layouts/index.html” download=“index.html” >}}
{{ define “main” }}
{{.Title}}
{{ with .Params.subtitle }}
{{.}}
{{ end }}
{{.Content}}
{{ range first 10 .Data.Pages }}
{{ .Render “summary”}}
{{ end }}
{{ end }}
{{< /code >}}
To effectively leverage section page templates, you should first understand Hugo’s content organization and, specifically, the purpose of _index.md
for adding content and front matter to section and other list pages.
The lookup order for section templates is as follows:
/layouts/section/<SECTION>.html
/layouts/<SECTION>/list.html
/layouts/_default/section.html
/layouts/_default/list.html
/themes/<THEME>/layouts/section/<SECTION>.html
/themes/<THEME>/layouts/<SECTION>/list.html
/themes/<THEME>/layouts/_default/section.html
/themes/<THEME>/layouts/_default/list.html
.Site.GetPage
with SectionsEvery 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’:
home
section
taxonomy
taxonomyTerm
{{< code file=“layouts/_default/section.html” download=“section.html” >}}
{{ define “main” }}
.Site.GetPage
The .Site.GetPage
example that follows assumes the following project directory structure:
.
└── content
├── blog
│ ├── _index.md # "title: My Hugo Blog" in the front matter
│ ├── post-1.md
│ ├── post-2.md
│ └── post-3.md
└── events #Note there is no _index.md file in "events"
├── event-1.md
└── event-2.md
.Site.GetPage
will return nil
if no _index.md
page is found. Therefore, if content/blog/_index.md
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/_index.md
, 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/_index.md
from which to pull content and front matter:
<h1>{{ with .Site.GetPage "section" "events" }}{{ .Title }}{{ end }}</h1>
Which then returns the following:
<h1>Events</h1>
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 page templates are lists and therefore have all the variables and methods available to list pages.
A taxonomy will be rendered at /PLURAL
/TERM
/ (e.g., http://spf13.com/topics/golang/) according to the following lookup order:
/layouts/taxonomy/<SINGULAR>.html
/layouts/_default/taxonomy.html
/layouts/_default/list.html
/themes/<THEME>/layouts/taxonomy/<SINGULAR>.html
/themes/<THEME>/layouts/_default/taxonomy.html
/themes/<THEME>/layouts/_default/list.html
A taxonomy terms page will be rendered at example.com/<PLURALTAXONOMYNAME>
/ (e.g., http://spf13.com/topics/) according to the following lookup order:
/layouts/taxonomy/<SINGULAR>.terms.html
/layouts/_default/terms.html
/themes/<THEME>/layouts/taxonomy/<SINGULAR>.terms.html
/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.
A Taxonomy is a map[string]WeightedPages
.
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:
WeightedPages is simply a slice of WeightedPage.
type WeightedPages []WeightedPage
Taxonomies can be ordered by either alphabetical key or by the number of content pieces assigned to that key.
<ul>
{{ $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 }}
</ul>
<ul>
{{ $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 }}
</ul>
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.
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:
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>
).
<ul id="tags">
{{ range .Params.tags }}
<li><a href="{{ "/tags/" | relLangURL }}{{ . | urlize }}">{{ . }}</a> </li>
{{ end }}
</ul>
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:
{{ 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.
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:
<ul>
{{ range .Site.Taxonomies.series.golang }}
<li><a href="{{ .Page.RelPermalink }}">{{ .Page.Title }}</a></li>
{{ end }}
</ul>
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.
<section id="menu">
<ul>
{{ range $key, $taxonomy := .Site.Taxonomies.featured }}
<li> {{ $key }} </li>
<ul>
{{ range $taxonomy.Pages }}
<li hugo-nav="{{ .RelPermalink}}"><a href="{{ .Permalink}}"> {{ .LinkTitle }} </a> </li>
{{ end }}
</ul>
{{ end }}
</ul>
</section>
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:
<ul id="all-tags">
{{ range $name, $taxonomy := .Site.Taxonomies.tags }}
<li><a href="{{ "/tags/" | relLangURL }}{{ $name | urlize }}">{{ $name }}</a></li>
{{ end }}
</ul>
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” >}}
.Site.GetPage
for TaxonomiesBecause 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” >}}
{{< /code >}}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.
/layouts/<TYPE>/<LAYOUT>.html
/layouts/<SECTION>>/<LAYOUT>.html
/layouts/<TYPE>/single.html
/layouts/<SECTION>/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/<TYPE>/<LAYOUT>.html
/themes/<THEME>/layouts/<SECTION>/<LAYOUT>.html
/themes/<THEME>/layouts/<TYPE>/single.html
/themes/<THEME>/layouts/<SECTION>/single.html
/themes/<THEME>/layouts/_default/single.html
Content pages are of the type page
and will therefore have all the page variables and site variables available to use in their templates.
post/single.html
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” }}
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.
These alternative content views are especially useful in list templates.
The following are common use cases for content views:
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/
li.html
single.html
summary.html
▾ project/
li.html
single.html
summary.html
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/
li.html
single.html
summary.html
The following is the lookup order for content views:
/layouts/<TYPE>/<VIEW>.html
/layouts/_default/<VIEW>.html
/themes/<THEME>/layouts/<TYPE>/<VIEW>.html
/themes/<THEME>/layouts/_default/<VIEW>.html
The following example demonstrates how to use content views inside of your list templates.
list.html
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” >}}
summary.html
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” >}}
li.html
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” >}}
[taxonomylists]: /templates/taxonomy-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 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 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:
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
:
<ul>
{{ range .discography }}
<li>{{ . }}</li>
{{ end }}
</ul>
Discover a new favorite bass player? Just add another .toml
file in the same directory.
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."
Achievements:
- "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.
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.
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 := "https://api.github.com" }}
{{ $gistJ := getJSON $urlPre "/users/GITHUB_USERNAME/gists" }}
This will resolve internally to the following:
{{ $gistJ := getJSON "https://api.github.com/users/GITHUB_USERNAME/gists" }}
Finally, you can range over an array. This example will output the
first 5 gists for a GitHub user:
<ul>
{{ $urlPre := "https://api.github.com" }}
{{ $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 }}
</ul>
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” >}}
Name | Position | Salary |
---|---|---|
{{ index $r 0 }} | {{ index $r 1 }} | {{ index $r 2 }} |
The expression {{index $r number}}
must be used to output the nth-column from the current row.
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
.
Currently, you can only use those authentication methods that can be put into an URL. OAuth and other authentication methods are not implemented.
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.
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 %}}
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:
layouts/partials/*<PARTIALNAME>.html
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.
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 %}}
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
.
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.country .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.
header.html
The following header.html
partial template is used for spf13.com:
{{< code file=“layouts/partials/header.html” download=“header.html” >}}
{{ partial "meta.html" . }}
<base href="{{ .Site.BaseURL }}">
<title> {{ .Title }} : spf13.com </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 %}}
footer.html
The following footer.html
partial template is used for spf13.com:
{{< code file=“layouts/partials/footer.html” download=“footer.html” >}}
{{< /code >}}themes: /themes/
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 %}}
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.
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 templates have a simple lookup order:
/layouts/shortcodes/<SHORTCODE>.html
/themes/<THEME>/layouts/shortcodes/<SHORTCODE>.html
You can create shortcodes using the following types of parameters:
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.
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 }}
.Inner
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 /*/>}}
.Params
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
$.Page.Params
shortcode_color
field in a content’s front matter could be accessed via $.Page.Params.shortcode_color
).$.Page.Site.Params
.IsNameParams
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.
The following are examples of the different types of shortcodes you can create via shortcode template files in /layouts/shortcodes
.
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 >}}
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” >}}
{{< /code >}}{{< code file=“youtube-embed.html” copy=“false” >}}
{{< /code >}}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=“content-image.md” >}}
{{</* 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” >}}
{{< /code >}}Would be rendered as:
{{< code file=“img-output.html” copy=“false” >}}
{{< /code >}}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 }}
Would be rendered as:
{{< code file=“vimeo-iframes.html” copy=“false” >}}
highlight
The following is taken from highlight
, which is a built-in shortcode that ships with Hugo.
{{< code file=“highlight-example.md” >}}
{{</* highlight html */>}}
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” >}}
<html>
<body> This HTML </body>
</html>
{{% 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 %}}
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” >}}
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">
</div>
<img src="/images/three.jpg">
More shortcode examples can be found in the shortcodes directory for spf13.com and the shortcodes directory for the Hugo docs.
[youtubeshortcode]: /content-management/shortcodes/#youtube “See how to use Hugo’s built-in YouTube shortcode.”
With Hugo’s readDir
and readFile
template functions, you can traverse your website’s files on your server.
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:
readDir
Example: List Directory FilesThis 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 %}}
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 ContentAs 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”>}}
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/
404.html
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 >}}
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:
ErrorDocument 404 /404.html
in an .htaccess
file in the root of your site.error_page 404 /404.html;
in your nginx.conf
file.errors { 404 /404.html }
. Details herepagevars: /variables/page/
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” >}}