Hugo Tutorial: Themeless & Gitless Introduction to the Hugo SSGUpdated  2022-May-16

News

Ongoing  According to Repology, the latest packaged Hugo is version . To keep up with Hugo releases, see github.com/gohugoio/hugo/releases, discourse.gohugo.io/c/announcements, or twitter.com/@GoHugoIO.

2022-March-14  Changed the URL of this article from www.ii.com/themeless-gitless-intro-hugo/ to www.ii.com/hugo-tutorial/. If you notice any issue related to this change, please post in the Comments and questions section below.

2021-May-31  As of today, this evolving⁠[1] article has been on the web for 2 years.🎂🎂

Prerequisites

Background

This tutorial assumes you have experience…

1. creating simple HTML+CSS websites

2. and launching apps from the command line.

It’s not essential, but may make it easier for you to understand the big picture of how Hugo works if you also have experience…

Mindset

Also this tutorial assumes you…

• would like to learn about some of the inner workings of Hugo

• and are comfortable tinkering with code.

In other words, this tutorial is for you if you are a “hacker” in the following sense.

hacker

“A person who delights in having an intimate understanding of the internal workings of a system, computers and computer networks in particular. The term is often misused in a pejorative context, where "cracker" would be the correct term. See also: cracker”

Tools

This tutorial does not assume anything about what platform and apps (other than Hugo) that you are using.

Extended Hugo

To follow the steps in this tutorial, you need to have an extended version of the static site generator Hugo installed on your system. Information about this is in step 0 and step 1 below.

Editor, terminal, and browsers

To develop a website with Hugo, you need to be able to access the following interfaces or views of your system.

InterfaceUsed For

command line
(CLI)⁠[2]

running hugo commands, including starting and stopping the Hugo server

web browser

viewing http://localhost:1313/

file browser

viewing and managing Hugo-related files and directories

plain text editor

editing the website’s archetypes, assets, configuration, content, and layout files

Most platforms have built-in apps for accessing the above four interfaces. If you would like to use an app that integrates some of these interfaces, I recommend one of the following.

• Code, which is also known as Visual Studio Code and VS Code

Both of these run on multiple platforms, are free/gratis,⁠[3] and are Free/Libre Open Source Software (FLOSS).

For more about integrated development environments, see the following pages at wikipedia.org.

Shell tip🐚

When you use a terminal emulator to interact with an operating system, you do it in a shell, which is a layer or interface between you and the operating system. I’ve tried to write this article so that the commands work in most shells. The main shell advice I have is the following.

 💡 Use a shell that saves the command-line history (or buffer) between sessions. This way you can use the Up Arrow and Down Arrow keys to step through your command history.On Unix-like platforms, most command-line shells (bash, fish, zsh, etc.) do this by default.On Windows, PowerShell and Git Bash save the command-line buffer by default, but cmd.exe⁠[4] does not. This is one reason I’d rather use Git Bash or PowerShell than cmd.exe.

My Hugo preferences

Website source files below $HOME (~) In the steps below we create a website out of files in a directory named Hugo. I recommend that you put this Hugo directory somewhere below your home directory because… 1. most backup apps automatically back up your home directory, 2. most sync apps, such as Dropbox and sync.com, sync a subdirectory of the home directory,[5] 3. you and hugo should not have permission problems creating, editing, moving, or deleting files and directories in your home directory, 4. and in most command-line shells, you can use cd ~ to go to your home directory.[6] To find out your home directory, open a terminal and at the command-line prompt run one of the following commands. • In PowerShell and Unix-like shells, run either… • echo$HOME

• or cd ~ (this will change directory to ~ (your home directory)).

• In cmd.exe, run…

• set home

Non-standard Hugo preferences

There are some things I do in the steps below that you may wonder about if you have already used Hugo. The following list of my preferences will, I hope, help you to understand why things are the way they are in this tutorial.

• I want to deal with a minimal number of layout[7] files and I do not want to have to think about Hugo’s layout lookup order.

• The home page layout file can be named either home.html or index.html. I prefer to name it home.html because the word index is semantically overloaded in Hugo.

• For Hugo configuration, I prefer YAML to TOML[8] and thus use a config.yaml file rather than a config.toml file. Many Hugo themes and tutorials use a config.toml.

• In YAML syntax, I like to minimize the use of commas, quotation marks, and square brackets.

IconMeaning

Important

Note

💡

Tip

0. Install extended hugo

To learn how to install extended Hugo, see Infinite Ink’s Installing Extended Hugo.

1. Check your hugo with the hugo version command

To check that hugo is on your path and that it’s an extended version, run this at a command-⁠line prompt:

hugo version

You should see something like this:

hugo v0.99.0-1de333e7a3fc863672ec6d6cd53ba66dbcdd2305+extended windows/amd64 BuildDate=2022-05-16T08:10:56Z VendorInfo=gohugoio
👆

 💡 You can get more information about your version of Hugo with the hugo env and hugo env -v⁠[9] commands.You can find out which directory the hugo executable is in with one of the following shell commands.In a Unix-like shell, including Git Bash, run:which hugoIn PowerShell, run:gcm hugo (or equivalently Get-Command hugo)In cmd.exe or Git Bash, run:where hugo

2. View Hugo’s built-in help

To learn about Hugo’s commands and flags run this command at a command-line prompt:

hugo -h | more

The trailing | more (“pipe more”) in the above command pipes[10] the output of hugo -h through the more pager. Within more, you can press Space to page down and press q to quit.

 ℹ -h, --help, and help are equivalent hugo command-line arguments. The results are on Infinite Ink’s Hugo CLI page.| more, which is equivalent to |more (with no whitespace), works in the command-line interface of most platforms, including BSD, Linux, macOS, Unix, and Windows.[11][12]

3. Create Hugo and Backups directories

Create a directory named Hugo, which will contain the Hugo-related files and directories we use in this tutorial. Within this directory, create a subdirectory named Backups. You should now have this directory structure:

Hugo/
Backups/
 💡 You might want to put this Hugo directory somewhere below your home directory (which is sometimes known as ~). Details about this tip are in My Hugo preferences above.If you are on a device running Windows, you might want to put a shortcut to this Hugo directory on your desktop. To learn about this tip, see Infinite Ink’s Windows Desktop Shortcuts Give me Quick Access to Anything.

4. Download the TGIH site skeleton

Download the site skeleton from the themeless-gitless-intro-hugo repository in Infinite Ink’s GitHub account. One way to download it is to click the following link of the repo’s .zip file.

After themeless-gitless-intro-hugo-master.zip has downloaded, unzip it and then put the TGIH[13] subdirectory in your Hugo directory. Your Hugo directory will now look like this:

Hugo/
Backups/
TGIH/

Before we edit the TGIH files, make a backup copy of the freshly downloaded and unzipped TGIH directory and include some historical information in the name of this backup directory, for example you could append the download date like this:

Hugo/
Backups/
TGIH-2022-05-16/
TGIH/

The Backups/TGIH-2022-05-16/ directory will come into play only if there is a problem with the website.

4.1. Explore the TGIH directory

The TGIH directory currently looks like this:

  TGIH/
archetypes/
default.md
assets/
style.scss
content/
articles/
markdown-experiments.md
layouts/
_default/
baseof.html
home.html
list.html
single.html
tag.html
static/
images/
go-logo_black.png
config.yaml

4.1.1. No themes directory

If you are familiar with Hugo, you may wonder why there is no themes/ directory. A themes/ directory is not required and the site we build below does not use one — that’s why this tutorial’s subtitle is Themeless & Gitless Introduction to the Hugo SSG.

4.1.2. Terminology: “project root directory”

For the rest of this article we work in this TGIH/ directory, which is called the…

• project base directory,

• project root directory,

• project working directory,

• project directory,

• project root,

• root,

• or workingdir.

4.2. Provenance

Most of the files in this directory were forked from Niklas Fasching's Hugo whitespace theme. The article markdown-experiments.md was forked from markdown-it. The image go-⁠logo_black.png is the Go logo.

Thank you Niklas, markdown-it, and golang.org!

5. Build and view the site

These files are enough to build the beginning of a website.

5.1. Build the site

At a command-line prompt, go to the TGIH directory and run:

hugo server -D
👆

The -D flag, which is equivalent to the --buildDrafts flag, tells the hugo server command to build drafts.

The Hugo server displays a lot of information, including something like this at the top:

Start building sites …

| EN
+------------------+----+
Pages            | 15
Paginator pages  |  0
Non-page files   |  0
Static files     |  1
Processed images |  0
Aliases          |  0
Sitemaps         |  1
Cleaned          |  0

Built in 100 ms

And this at the bottom:

Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
 ℹ The time it takes to build the website depends on the computer you are using.100 ms (milliseconds) is ⅒th of a second!🚀

5.2. View the site

In a web browser, go to…

http://localhost:1313/
👆
notice that this is not https

You should see something like the following.

Click on the yellow highlighted Markdown Experiments link and you will see a page that contains HTML elements, such as headers, lists, italicized text, and bolded text. The hugo command generated this HTML page from the file content/articles/markdown-experiments.md. Details about this .md file are in step 6 below.

5.3. Explore the TGIH directory again

In a file browser, note that the hugo server command generated a resources/_gen/ directory so now the TGIH directory looks like this:

  TGIH/
archetypes/
default.md
assets/
style.scss
content/
articles/
markdown-experiments.md
layouts/
_default/
baseof.html
home.html
list.html
single.html
tag.html
resources/
_gen/
assets/
scss/
style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content
style.scss_f300667da4f5b5f84e1a9e0702b2fdde.json
images/
static/
images/
go-logo_black.png
config.yaml

5.4. Hugo server tips

• If you leave this hugo server running, Hugo will LiveReload the site when you make changes.

• While the server is running, you can open another terminal and run other hugo commands there. If you regularly use multiple terminals, I recommend using a tabbed terminal emulator.

• If there is a problem with the site, use Ctrl+C to stop the Hugo server and then restart it.

For more Hugo server tips, see Infinite Ink’s Debugging Your Hugo Website.

6. Anatomy of a content file (markdown-⁠experiments.md)

This section is about looking at a file in the content/ directory. You do not need to make any edits, but it’s OK if you do.

Use your text editor to open markdown-experiments.md, which is in the content/articles/ directory. Abstractly a Hugo content file is structured like this:

body

In Hugo the header is called front matter and the body is called various things, including:

• body

• body content

• Content

• content body

• main matter

• RawContent

In this Hugo tutorial, the body is called Content (with the “C” capitalized). Here is the anatomy of a Hugo content file using this terminology:

front matter

Content

Details are below.

6.1. Front matter

The file begins with with three dashes[15] (---). These dashes tell the hugo command that what follows is YAML front matter. Front matter is used to set page variables. For more information, see these pages on the gohugo.io site:

Front matter is also known as metadata. A Hugo variable is also known as a parameter (or more precisely as a parameter key and a parameter value).

 ‼ Front matter is required in a Hugo content file. If you do not need to specify any metadata, use empty front matter, for example this:--- ---or this:--- # This YAML front matter is intentionally left blank. ---

6.2. Blank line

After the YAML front matter, which ends with ---, is a blank line.

 ℹ If the front matter is in TOML or YAML format, this blank line is not required but if the front matter is in JSON format, it is required.

6.3. Content

After the blank line is the Content. Since the filename extension is .md, the hugo command interprets this part of the file as Markdown, a lightweight markup language.

 ℹ I use “Content” — with an initial capital letter — to mean the part of the file after the front matter.In Go Templates, which are discussed in steps 11 and 15 below, this Content is sometimes available as {{ .Content }} and {{ .RawContent }}.

7. Content, configuration, and front-matter languages

7.1. Content markup languages

Hugo supports a lot of markup languages, including more than one flavor of Markdown. In this tutorial, all content files are interpreted as Goldmark-flavored Markdown (assuming you are using Hugo v0.60.0⁠[16] or newer).

7.2. Configuration and front-matter languages

In Hugo, you can use JSON, TOML, or YAML in…

1. front matter of content files,

2. site configuration files,

3. and data files.

In this tutorial, we use YAML for the first two and do not use the third (data files).

8. Create one.md

Open a new terminal, make sure you are in the TGIH directory, and run:

hugo new articles/one.md
---------------
👆
this path is relative to TGIH/content/

The one.md file is created in the content/articles/ directory.

 ℹ Do not specify content in the path because that is included automatically by the hugo new commandIn Hugo forward slash (/) will work as a directory delimiter on any platform, including Windows.Do not put a space or any whitespace character in the path or file name.Separate words with a dash (-)[15] because the new-content archetype (discussed in step 11 below) creates the article title by replacing dashes with spaces.Use all lower case characters in the names of directories and files in the content/ directory because most web servers force URL paths to be all lower case.⁠[17]In Hugo, the default is to use the content file name (without the file extension) as part of the web page URL.[18]

Your TGIH/content/ directory now looks like this:

content/
articles/
markdown-experiments.md
one.md

Look at http://localhost:1313/ in a web browser and the One and Markdown Experiments articles should be listed on the home page like this:

 💡 If you do not see both the One and Markdown Experiments articles listed, make sure:hugo server is running with the -D flagone.md is located in the articles/ directory

9. Edit one.md

Use a text editor to open one.md, which looks like this (with the date replaced with the date you created it):

---
# Important: If this is not a draft, comment out the next line
draft: true
title: One
date: 2019-05-16
# below are non-built-in parameters (lower case keys recommended)
subtitle:
tags:
- hugo
- intro
---

Below the blank line after the front matter add some markdown content, for example:

**Hello World!** This is written in *Markdown*, a lightweight markup language.

When you save your changes, the Hugo server will automatically update the markdownified web page. In Hugo markdownify means convert markdown to HTML.

9.1. Learn Markdown

To learn Markdown, see:

 💡 A nice FLOSS multi-platform WYSIWYG Markdown editor is Mark Text. If you are on Windows, you may also want to check out Markdown Monster.

10. Edit config.yaml🔧

The config.yaml file in the root of the TGIH directory is used to specify global variables. Use a text editor to open this file, which looks like this:

baseURL: https://example.org/
languageCode: en-us
title: My New Hugo Site

10.1. title

Use your text editor to add a comment, a blank line, and change the title to Hello World. The file will now look something like this:

# 2022-05-16: changed title

baseURL: https://example.org/
languageCode: en-us
title: Hello World

If the hugo server is running and the web browser is displaying http://localhost:1313/, the title will immediately change to Hello World when you save config.yaml.

 ‼ In a Hugo config file, variables, such as baseURL, languageCode, and title, are sometimes case sensitive so I recommend that you specify them using the upper- and lower-case letters that are specified in gohugo.io/getting-started/configuration/. For details, see Infinite Ink’s Variable and Parameter Names in Hugo (featuring camelCase⁠🐫 and snake_case⁠🐍).

In Hugo, there are many ways to specify global variables, including

• in a file named config.json, config.toml, or config.yaml in the root of the project

• in environment variables

To me, the simplest is to use config.yaml in a project’s root so that is what I use in this tutorial.

To view your site’s current configuration, which includes a lot of default settings, run the following command from the TGIH directory:

hugo config | more

11. Edit the archetype for new .md content files

When you use the hugo new command to create a .md file (as we did in step 8 above), Hugo uses archetypes/default.md as a template for the new file.

11.1. Open and view archetypes/default.md

Use a text editor to open default.md, which looks like this:

---
## Important: If this is a draft, next line should NOT begin with #
# draft: true
title: {{ replace .Name "-" " " | title }}
date: {{ dateFormat "2006-01-02" .Date }}
## below are user-defined parameters (lower case keys recommended)
subtitle:
tags:
- tag1
- tag2
---

11.1.1. Front matter

The double curly braces in the title and date key values are Go Template code.

 ℹ A curly brace is sometimes called a mustache or handlebar, but Go Templates are different from Mustache and Handlebar templates.

11.1.2. Content

Currently the Content part of this archetype file is empty. You can write some notes to yourself, some content snippets, or whatever you would like to be included in every .md file created with the hugo new command. For example, you could put something like the following bolded lines in the content part of your markdown archetype file.

---
## Important: If this is a draft, next line should NOT begin with #
# draft: true
title: {{ replace .Name "-" " " | title }}
date: {{ dateFormat "2006-01-02" .Date }}
## below are user-defined parameters (lower case keys recommended)
subtitle:
tags:
- tag1
- tag2
---

markdown here

<!--
HTML, including an HTML comment like this, is OK in markdown
-->

HTML comments will not appear on a web page, but may be viewable if someone uses a web browser to “view page source” so be careful what you put in HTML comments.[19]

11.1.3. Go Template code works anywhere in an archetype file

You can include Go Template code anywhere in an archetype file, including in the Content section. I like to have an HTML comment that records the exact moment that I created the file by putting this in the Content section of my archetype file:

<!--
created {{ now }}
-->

The above HTML comment is a note to self that my readers will not see unless they use their web browser to “view page source.”⁠[19]

11.2. Edit archetypes/default.md

In step 12 below we create more Markdown content. In order to see how an archetype works, add the bolded text below to the Content part of default.md:

---
## Important: If this is a draft, next line should NOT begin with #
# draft: true
title: {{ replace .Name "-" " " | title }}
date: {{ dateFormat "2006-01-02" .Date }}
## below are user-defined parameters (lower case keys recommended)
subtitle:
tags:
- tag1
- tag2
---

markdown here

<!--
created {{ now }}
-->

11.3. Save and close archetypes/default.md

Close the default.md archetype file so you do not accidentally edit it in the steps below.

11.4. Archetype references and tips

For more about Hugo archetypes, see:

 💡 In Go Templates, including Hugo archetypes, layouts, and shortcodes,…Functions use prefix notation, which is also known as Polish notation. For example, the syntax of the dateFormat function is dateFormat LAYOUT INPUT. This function is used in step 11.1 above.The LAYOUT string 2006-01-02 in step 11.1’s dateFormat function is based on the Go reference date. To learn about this, see Dates in Hugo⁠📆 in Infinite Ink’s Hugo Shortcodes.You can keep things DRY by using partials, which are basically Go-Template “includes.” This is useful if you have something that you want to include in multiple layout, shortcode, and/or archetype files and you Don’t want to Repeat Yourself. Note that partials reside in your project’s layouts/partials/ directory.

12. Create more content: another-one.md and about.md

Thanks to the updates to the archetype file we made in the last step, the .md files we create in this step will include some default text below the front matter.

At a command-line prompt, make sure you are in the TGIH directory, and run these two commands:

hugo new articles/another-one.md
hugo new about.md

The content directory now looks like this:

content/
articles/
another-one.md
markdown-experiments.md
one.md

13. Experiment with the content .md files

In a text editor open about.md, another-one.md, markdown-experiments.md, and one.md. Note that about.md and another-one.md include the Content that we added to the archetype file in step 11.2.

13.1. Front matter

In the front matter, experiment with the following parameters.

13.1.1. draft

The beginning of the front matter in most of the .md files looks like this:

---
## Important: If this is a draft, next line should NOT begin with #
# draft: true

Turn at least one of these content files into a draft by changing the front matter to the following (i.e., remove the #  that is before draft: true).

---
## Important: If this is a draft, next line should NOT begin with #
draft: true
 ℹ If a content file is a draft, the hugo command will process it only if the --buildDrafts flag, which is equivalent to the -D flag, is used.

13.1.2. date

The order of the articles listed on the home page (http://localhost:1313/) is based on the date parameter. Change the dates so that the order is changed.

 ‼ Make all dates today or earlier. By default hugo does not build any page with a date in the future.

To learn about other ways to order the article list, see Order Content at gohugo.io.

13.1.3. subtitle

The front matter includes a subtitle parameter key that has no value:

subtitle:

In some or all of the .md files add a value to this key, for example:

subtitle: this is a subtitle

Make sure to leave a space between the colon (:) and the subtitle value.

13.2. Content

After the YAML front matter, which ends with three dashes (---), I like to put a blank line before the Markdown Content.

 ℹ If the front matter is in TOML or YAML format, this blank line is not required but if the front matter is in JSON format, it is required.

13.2.1. Include images🖼️

13.2.1.1. Include a remote image

To include a remote image, use Markdown syntax like this:

![fractal](https://upload.wikimedia.org/wikipedia/commons/d/d6/Finite_subdivision_of_a_radial_link.png)

After Hugo builds the website, this will be rendered in a web browser like this:

13.2.1.2. Include a local image

The TGIH directory that you downloaded in step 4 includes an image in the static/ subdirectory. To use this image in a TGIH .md file, you can use this Markdown syntax:

![Go Logo](/images/go-logo_black.png)
👆
notice this leading slash

When you save the .md file with this Markdown, the following image will be displayed in your web browser.

This is the Go logo, which you can read about at blog.golang.org/go-brand.

13.2.1.3. Image tips

The text inside the above Markdown image square brackets is used as the alt attribute of the rendered HTML img tag (<img alt="Go Logo" … >). To specify other aspects of an image, such as size, you could use one of the following instead of this Markdown image syntax:

 ℹ In markup languages, such as HTML and Markdown, an image is usually not included, instead it is referenced.⁠[20]Since the path to the local image begins with a slash (/), it is an absolute path with respect to the site baseURL.[21] Details about the structure of the built TGIH directory are below in step 17.3. Explore the public directory and step 17.4 Source files, destination files, and pretty URLs.

13.2.2. Include emoji codes

Include the following three emoji codes in the Content of at least one of the .md files.

:man_astronaut:
:star:
:woman_astronaut:
 ‼ These will not be rendered as emoji[22] until step “14.1 enableEmoji✨” below.

 ℹ You can find emoji codes, which are also known as emoji shortcodes and CLDR short names, at:an emoji cheatsheet such as github.com/ikatyang/emoji-cheat-sheet/blob/master/README.md or webfx.com/tools/emoji-cheat-sheet (formerly known as emoji-cheat-sheet.com)emojipedia.orgfileformat.info/info/emoji/list.htmunicode.org/emoji/charts/full-emoji-list.htmlAccording to discourse.gohugo.io/t/support-github-emoji/6164/2, the Hugo emoji codes come from github.com/kyokomi/emoji.

 💡 ⇽This tip icon is the :bulb: emoji.The titles of steps 14 and 14.1 below include, respectively, the :wrench: and :sparkles: emoji.

14. Edit config.yaml again🔧

Open config.yaml in a text editor.

14.1. enableEmoji✨

Add something like the following four lines to your config.yaml. I like to surround a setting like this with blank lines to make it stand out from other configuration settings, especially any table or list, that might be above or below it.


enableEmoji: true


As soon as you save config.yaml, the three emoji codes you specified above in step 13.2.2 should render in the web browser as:

👨‍🚀 ⭐ 👩‍🚀

14.2. markup

If you are using Hugo v0.60.0+ and want to use raw HTML in your Markdown, include the following nested map (or a superset of it) in your config.yaml.[23][24]


markup:
goldmark:
renderer:
unsafe: true


With this “unsafe” setting, Hugo will pass raw HTML — for example <br> — through to the destination file.

 ‼ Without this “unsafe” setting, 
and any other raw HTML in a Markdown source file will be replaced with  in the markdownified[25] destination file.

Note that this setting is needed only if you are using Hugo’s default Markdown parser (Goldmark). For more about this, see…

15. Explore the layouts directory

The layouts directory looks like this:

layouts/
_default/
baseof.html
home.html
list.html
single.html
tag.html

These files — along with the .scss file in the assets/ directory — create the look and feel of the website.

Each Hugo layout file…

The TGIH website has three kinds of pages and Hugo renders them as follows:

Kind[26]Uses base layout
baseof.html and
main block
from…
View example
rendering at

home

home.html[27]

localhost:1313/

page

single.html

term

tag.html

localhost:1313/tags/tag1/

15.2. Edit home.html

Open home.html in a text editor. The following line is why drafts are highlighted in yellow on the home page.

<span {{ if .Draft }}style="background-color: yellow;"{{ end }}>{{ .Title }}</span>

Change yellow to red, blue, green, rebeccapurple, gray, lightgray, or any of the hundreds of web colors.

Next add some HTML under the h1 heading, for example:

<h1 class="title">{{ .Title }}</h1>

<!-- 2022-05-16: added next paragraph -->
<p>
Here are the articles on this website <strong>ordered by publication date</strong>, starting with the most recently published article.
</p>

This added paragraph is written in HTML, which is why it is within the HTML <p> and </p> tags. (Note that when you write in a lightweight markup language, such as Markdown, you do not need to use paragraph tags because paragraphs are delimited by blank lines.)

When you save these changes, the home page of the site (http://localhost:1313/) will change the draft highlight color and display the text that you put between <p> and </p>.

 ℹ Another way to add text to the home web page is discussed in Infinite Ink’s Introduction to Hugo Bundles in the section Branch bundle example.

15.3. Layout references and tips

 ℹ In Go HTML…You can comment out executable code with the following comment syntax.{{/* Go HTML multi-line comment */}}Functions use prefix notation, which is also known as Polish notation. For example, the syntax of the dateFormat function is dateFormat LAYOUT INPUT. This function is used in step 11.1 above.The LAYOUT string 2006-01-02 in step 11.1’s dateFormat function is based on the Go reference date. To learn about this, see Dates in Hugo⁠📆 in Infinite Ink’s Hugo Shortcodes.You can keep things DRY by using partials, which are basically Go-Template “includes.” This is useful if you have something that you want to include in multiple layout, shortcode, and/or archetype files and you Don’t want to Repeat Yourself. Note that partials reside in your project’s layouts/partials/ directory.

16. Explore the assets directory

The assets directory looks like this:

    assets/
style.scss

style.scss is the stylesheet for the TGIH website.

To learn about the Hugo assets directory, which is where global resources are located, see gohugo.io/hugo-pipes/introduction/.

style.scss is written in Sassy CSS, which is a superset of CSS. SCSS supports the following two types of comments.

• /*
CSS
multi-line
comment
*/
• // SCSS single-line comment

For more about SCSS commenting, see Sass Comments at sass-lang.com. For information about SCSS in general, see Sass (stylesheet language) at wikipedia.org.

In the next section we use SCSS single-line comments.

16.3. Edit style.scss🎨

Open assets/style.scss in a text editor and insert a comment that says something like this:

// 2022-05-16: changed $highlight variable Next change the $highlight variable to whatever color you would like to use for headers and other highlighted text in the site. I recommend making a backup of the original $highlight setting by commenting out the original line. style.scss will now look something like this: // 2022-05-16: changed$highlight variable

// $highlight: rgb(250, 100, 50);$highlight: blue;

When you save this change, the header colors will immediately change from rgb(250, 100, 50)      to blue      in all pages of http://localhost:1313/.

17. Prepare for publication

When you are ready to publish your site at a web-hosting provider, you will run the hugo command without the server subcommand. This will create the for-publication site files in the TGIH/public/ directory.

17.1. Test build without -D or --buildDrafts

In the TGIH directory, run:

hugo server
👆
no flag here

In a web browser, view http://localhost:1313/ and make sure that only the files that are ready for publication are built.

If an article is not ready for publication, its front matter should include this:

draft: true

If it is ready for publication, its front matter should include this:

# draft: true

Commenting out the draft key works because Hugo’s default is draft: false. If you prefer, you could change draft: true to draft: false, rather than commenting out the draft key.

 💡 To list all drafts, run hugo list drafts at a command-line prompt. Details about the hugo list command are at www.ii.com/hugo-cli/#_hugo_list_help.

17.2. Run hugo without subcommands or flags

In the TGIH directory, run:

hugo
👆
no subcommands or flags

17.3. Explore the public directory

The hugo command creates a directory named public/ in the TGIH/ directory. If none of the .md files in the content/ directory have draft: true in the front matter, the following will be the structure of this TGIH/public/ directory.

|   index.html
|   index.xml
|   sitemap.xml
|   style.css
|
|       index.html
|
+---articles
|   |   index.html
|   |   index.xml
|   |
|   +---another-one
|   |       index.html
|   |
|   +---markdown-experiments
|   |       index.html
|   |
|   \---one
|           index.html
|
+---categories
|       index.html
|       index.xml
|
+---images
|       go-logo_black.png
|
\---tags
|   index.html
|   index.xml
|
+---markdown
|       index.html
|       index.xml
|
+---tag1
|       index.html
|       index.xml
|
+---tag2
|       index.html
|       index.xml
|
\---testtesttest
index.html
index.xml


To learn about sitemaps, including sitemap.xml, which is the third line in the directory tree above, see Infinite Ink’s Hugo and sitemap.txt.

The above two emphasized lines are discussed in the next section.

17.4. Source files, destination files, and pretty URLs

When you build a website with the above hugo command, the files and directories in the static/[28] directory, which are emphasized in the directory tree above, are simply copied to the public/[29] directory. A non-static file is processed by hugo and its destination is determined by configuration settings, layout files, the file’s file extension, and the file’s front matter.

The table below shows how some of the TGIH source files are transformed from source to destination to URL (viewable in a web browser after deployment). Some of the TGIH source files are listed in step 4.1 Explore the TGIH directory above.

source in TGIH/destination in
TGIH/public/
URL (if baseURL
is ii.com/)

static/images/go-
logo_black.png

images/go-
logo_black.png

ii.com/images/go-
logo_black.png

assets/style.scss

style.css

ii.com/style.css

content/articles/one.md

articles/one/index.html

ii.com/articles/one/

The last two URLs in the URL column above, which are bolded, are called pretty URLs[30] because they do not end with a file extension (.aspx, .cgi, .css, .htm, .html, .mhtml, .php, .png, .shtml, .xhtml, .xml, etc.).

For more about all this, see:

Note that the above four gohugo.io URLs are “pretty.”

17.5. Edit config.yaml again🔧

Open config.yaml in a text editor.

17.5.1. baseURL

The baseURL setting is the bolded line below.

baseURL: https://example.org/
👆
notice this trailing slash

The slash (/) at the end of the baseURL can’t hurt[21] and sometimes helps, so I recommend that you include it.

When you are really ready to publish — rather than learning Hugo in this Hugo tutorial — replace example.org/ with your site’s domain name and path, for example:

• your.domain.name/

• your.domain.name/path/to/your/site/

• your.domain.name/blog/

 💡 Instead of setting baseURL to https://example.org/ or https://your.domain.name/, you can set it to simply / (slash) like this:baseURL: /This makes it easier to publish the site on a test domain and have all the intra-site links work. For example, with this setting the TGIH pages refer to the stylesheet as /style.css rather than https://your.domain.name/style.css.

17.5.2. taxonomies🏷️

Above in step 17.3. Explore the public directory, you can see that the hugo command created directories named categories and tags. These are Hugo’s default taxonomies. Since the TGIH website uses tags but not categories, we can clean things up by specifying the following table[23] in the config.yaml.

taxonomies:
tag: tags

This overrides Hugo’s default, which is:

taxonomies:
category: categories
tag: tags

To specify a taxonomy in Hugo, you specify the singular and plural forms of the taxonomy’s name. For example, the above tag: tags line specifies the singular and plural forms of the taxonomy used in the TGIH website. Note that the plural form is what is used in the front matter of a content file.

To learn about taxonomies in Hugo, see gohugo.io/content-management/taxonomies/.

 ‼ Hugo’s taxonomy terminology changed in v0.73.0, which was released 2020-June-23. Infinite Ink uses the v0.73.0+ terminology (taxonomy and term) but be aware that some old themes and old documents use the pre-v0.73.0 terminology (taxonomyTerm and taxonomy).A clue that a document is documenting Hugo v0.72.0 or earlier is if it contains the string taxonomyTerm without mentioning that this term is obsolete in Hugo v0.73.0+.

17.5.3. Case sensitivity of variables

 ‼ In a Hugo config file, variables, such as baseURL, languageCode, and title, are sometimes case sensitive so I recommend that you specify them using the upper- and lower-case letters that are specified in gohugo.io/getting-started/configuration/. For details, see Infinite Ink’s Variable and Parameter Names in Hugo (featuring camelCase⁠🐫 and snake_case⁠🐍).

17.6. Rebuild tip

If you use the hugo command to rebuild your site, it overwrites files in the public/ directory, but it does not delete files that are already there that are no longer used. If you publish everything in the public/ directory, people and bots browsing the web may stumble upon these old files.

To delete these old files, do one of the following.

• Delete the public/ directory before running hugo

• or use hugo --cleanDestinationDir, which deletes everything in the public/ directory other than the static files.

17.7. Useful build flags

In addition to --cleanDestinationDir, which was discussed in the previous step, you may want to use the --minify flag. This flag removes HTML comments and extraneous whitespace characters in the generated HTML files.

You can specify multiple flags like this:

hugo --cleanDestinationDir --minify

More build flags are listed on Infinite Ink’s Hugo CLI page.

18. Publish the site

To publish or deploy the site, copy all the files and directories in the public/ directory to the appropriate directory on your web-hosting provider’s server.

19. Possible next steps

19.1. Play with the exampleSite from a theme

This section is now part of Infinite Ink’s Easy Way to Play With a Hugo Theme’s Example Site.

This tutorial does not use bundles because I wanted to keep it simple, but when you read the Hugo documentation and play with example sites from themes, you will see files below the content/ directory named index.md and _index.md.⁠[31] A content file with either of these names is part of a Hugo bundle. To learn about this, see Infinite Ink’s Introduction to Hugo Bundles.

Debugging tips

This section is now part of Infinite Ink’s Debugging Your Hugo Website.

Thanks!

Thank you to…

In addition to the above, many other tools, resources, and people helped me create this article and move the Infinite Ink website into the world of 2019+ web development.⁠

Endnotes

1. Many Infinite Ink articles, including this one, are evergreen and regularly updated.
2. CLI is also known as command-line interface, command-line interpreter, command shell, console, console emulator, terminal, terminal emulator, or the command line. For more about this, see Infinite Ink’s #cli portal.
3. Free/gratis means free as in the phrase “free beer” (i.e., the price is \$0).
4. cmd.exe is also known as CMD and is pronounced “cee em dee.” It is sometimes referred to as the “Command Prompt” (which is a completely ambiguous name IMHO). Details are at Wikipedia’s cmd.exe.
5. If you use a “sync app,” such as Dropbox or sync.com, you may want to put your Hugo directory somewhere below ~/Dropbox or ~/Sync. To learn about these type of apps and services, see Infinite Ink’s My Primary Cloud Storage Provider is sync.com⁠☁️.
6. Using tilde (~) as a shortcut for the home directory works in PowerShell and nix-based shells, but does not work in cmd.exe.
7. Hugo layout files, which are also called templates, are written in Go HTML.
8. I prefer YAML to TOML mainly because I do not want to have to put all “TOML tables” at the bottom of the config.toml file. Instead I want to structure my config file in a way that makes sense to me. Also, using YAML for both front matter and the config file means I only need to remember the syntax of one of these data-serialization formats. Information about YAML is in Infinite Ink’s YAML Includes Atoms, Maps, and Lists (featuring the string ¯\_(ツ)_/¯).
9. Starting with Hugo v0.83.0, which was released 2021-May-1, hugo env -v lists the external dependencies that were used to build hugo.
10. A nice introduction to pipelines is Jessie Frazelle’s For the Love of Pipes.
11. Windows has many command-line shells, including cmd.exe, PowerShell, WSL Bash, and Git Bash.
12. The more command is not included in Git Bash, but the less command, which can do everything more can do (and more), is.
13. TGIH (for Themeless & Gitless Introduction to Hugo) will be the “working directory” for the rest of this tutorial.
14. In some terminal emulators, you can Ctrl-Click the URL’s port number and the URL will be launched in your default web browser. For example, to launch http://localhost:1313/ in your default web browser, Ctrl-Click 1313.
15. The Unicode name for the “dash” character (-) is “hyphen-minus,” but its proper name is rarely used. Instead, it is usually called “dash,” “hyphen,” or “minus.” Details are at wikipedia.org’s Hyphen-minus.
16. As of Hugo v0.60.0, which was released on 2019-November-27, Goldmark is the default Markdown parser, the Mmark Markdown parser is deprecated, and it was announced that the Blackfriday Markdown parser will eventually be deprecated.
17. If you want to use upper-case characters in a web page URL, put disablePathToLower: true in your config.yaml.
18. Actually bundle directory names are also used as part of a web page URL, but the TGIH website does not use content bundles.
19. HTML comments will be removed from the built HTML pages if you build with hugo --minify.
20. With Scalable Vector Graphics (SVGs), it is possible to actually include an image in an HTML file by using the <svg> tag. Information about using SVGs, including inline SVGs, is at svgontheweb.com/#implementation.
21. Double slashes in a path will be interpreted as one slash so, for example, https://example.org//images/go-logo_black.png is interpreted as https://example.org/images/go-logo_black.png.
22. The plural of “emoji” can be spelled “emoji” or “emojis.” To learn about pluralizing the word “emoji,” see merriam-webster.com’s definition of emoji and the second Q in emojipedia.org’s FAQ. Also see Infinite Ink’s #emoji Portal.
23. A nested map is also known as an associative array, a dictionary, a dict, a hash table, a hash, a keyed list, a map, a mapping, a named map, an object, a record, a struct, or a table. For more about this data-serialization object, see Infinite Ink’s YAML Includes Atoms, Maps, and Lists (featuring the string ¯\_(ツ)_/¯).
24. If this were a config.toml, rather than a config.yaml, the markup table would need to be placed at the bottom of the config file. I wrote about this above in Endnote 8 and on Infinite Ink’s Hugo Tips and Fragments in Fragment 3.
25. In Hugo markdownify means convert Markdown to HTML
26. .Kind is a built-in Hugo page variable and some of the possible values of this variable (for example “term”) changed in v0.73.0. To learn about this, see the Hugo v0.73.0 release notes and the tip in the Taxonomies section of Infinite Ink’s Hugo Tutorial.
27. The home page layout file can be named either home.html or index.html. I prefer to name it home.html because the word index is semantically overloaded in Hugo.
28. In Hugo, the static directory or directories can be specified with the staticDir parameter in a config file. The default is a single directory named static.
29. In Hugo, the name of the public directory can be specified with the publishDir parameter in a config file or with the hugo CLI flag -d (which is equivalent to -⁠-⁠destination).

Comments and questions 📝 🤔 👎 👍

Your public comment or question might immediately improve this page or help me to (eventually) improve this page.