Hugo Tutorial: Themeless & Gitless Introduction to the Hugo Static Site Generator
Updated 2021-August-25

Page contents


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




This tutorial assumes that you have experience…

  1. creating simple HTML+CSS websites

  2. and launching apps from a command line.

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



Also this tutorial assumes that 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.


“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”


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.

Interface Used For

command line

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.

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

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


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.

For more information about shells, see Shell (computing) - Wikipedia.

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 a subdirectory of the home directory,[4]

  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.[5]

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

Executable anywhere on $PATH

The hugo executable is one file — with no dependencies⁠🎉 — and it can be put anywhere on your path. To find out your path, run one of the following commands at a command-line prompt.

  • In a Unix-like shell, run:

    • echo $PATH

  • In PowerShell, run:

    • $Env:Path (or equivalently all lower case $env:path)

  • In cmd.exe, run:

    • set path

If you use a package manager to install hugo, you will not need to deal with your path because the package manager will take care of that.

Information about installing Hugo is in step 0 below.

Non-standard Hugo preferences

There are some things that 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[6] 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[7] 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.

Article style

This article uses the following admonition icons.

Icon Meaning





0. Install extended hugo

To install an extended version of hugo, do one of the following.



1. Check your hugo with the hugo version command

To check that hugo is on your path, is version 0.43 or newer and is an extended version, run this at a command-line prompt:

hugo version

You should see something like this:

hugo v0.88.1-5BC54738+extended windows/amd64 BuildDate=2021-09-04T09:39:19Z VendorInfo=gohugoio
Make sure you are using Hugo extended v0.43 or newer because old and unextended versions of Hugo do not support SCSS (Sassy CSS), which we use in the TGIH website we build below.


  • You can get more information about your version of Hugo with the hugo env and hugo env -v[11] 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 hugo

    • In PowerShell, run:

    • 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[12] 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.[13][14]

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:

  • 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 on the following link of the repo’s .zip file.

After has downloaded, unzip it and then put the TGIH[15] subdirectory in your Hugo directory. Your Hugo directory will now look like this:


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:


The Backups/TGIH-2021-09-05/ 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:



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 Static Site Generator.


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 was forked from markdown-it. The image go-⁠logo_black.png is the Go logo.

Thank you Niklas, markdown-it, and!

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
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…

   notice that this is not https

You should see something like the following.

screenshot of page titled My New Hugo Site

Click on the about link in the navigation bar and you will get a “404 page not found” page. We fix this in step 12 below.

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/ 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:



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-⁠

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, which is in the content/articles/ directory. Abstractly a Hugo content file is structured like this:



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


Details are below.

6.1. Front matter

The file begins with with three dashes[17] (---). 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 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⁠[18] 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

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

hugo new articles/
         this path is relative to TGIH/content/

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

  • Do not specify content in the path because that is included automatically by the hugo new command

  • In 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 (-)[17] 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.⁠[19]

  • In Hugo, the default is to use the content file name (without the file extension) as part of the web page URL.[20]

Your TGIH/content/ directory now looks like this:


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:

My New Hugo Site screenshot

If you do not see both the One and Markdown Experiments articles listed, make sure:

  • hugo server is running with the -D flag

  • is located in the articles/ directory

9. Edit

Use a text editor to open, 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)
  - 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:

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:

# 2021-09-05: changed title

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


10.2. About configuring Hugo

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 command-line flags

  • in environment variables

  • in multiple files in a config/ directory in the root of the project

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

For more information about configuring Hugo, see Configure Hugo at


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/ as a template for the new file.


11.1. Open and view archetypes/

Use a text editor to open, 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)
  - 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)
  - 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.[21]


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.”⁠[21]


11.2. Edit archetypes/

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

## 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)
  - tag1
  - tag2

markdown here

  created {{ now }}


11.3. Save and close archetypes/

Close the 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,…

  • 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: and

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/
hugo new

The content directory now looks like this:


In your web browser, note that the about link in the navigation bar of all the http://localhost:1313/ pages now works.👍

13. Experiment with the content .md files

In a text editor open,,, and Note that and 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


13.1.3. subtitle

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


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 an 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, 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 on the web page.

Go Logo

This is the Go logo, which you can read about at


The text inside this Markdown’s 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.



13.2.2. Include emoji codes

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

These will not be rendered as emoji[24] until step “14.1 enableEmoji✨” below.




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.

# 2021-09-05: added next line
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.[25][26]

      unsafe: true

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

Without this “unsafe” setting, <br> and any other raw HTML in a Markdown source file will be replaced with <!-- raw HTML omitted --> in the markdownified[27] 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:


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

15.1. About Hugo layout files

Each Hugo layout file…

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

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










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>

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


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

For more about…



  • You can comment out executable code with the following comment syntax.

         Go HTML
  • 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:


style.scss is the stylesheet for the TGIH website.


16.1. About the assets directory

To learn about the Hugo assets directory, which is where global resources are located, see


16.2. About SCSS

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

  • /*
  • // SCSS single-line comment

For more about SCSS commenting, see Sass Comments at For information about SCSS in general, see Sass (stylesheet language) at

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:

// 2021-09-05: 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:

// 2021-09-05: 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


17.2. Run hugo without subcommands or flags

In the TGIH directory, run:

     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
|   |   index.html
|   |   index.xml
|   |   
|   +---another-one
|   |       index.html
|   |       
|   +---markdown-experiments
|   |       index.html
|   |       
|   \---one
|           index.html
|       index.html
|       index.xml
|       go-logo_black.png
    |   index.html
    |   index.xml
    |       index.html
    |       index.xml
    |       index.html
    |       index.xml
    |       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 highlighted 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/[30] directory, which are highlighted in the directory tree above, are simply copied to the public/[31] 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
URL (if baseURL









The last two URLs in the URL column above, which are bolded, are called pretty URLs[32] 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 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.

                            notice this trailing slash

The slash (/) at the end of the baseURL can’t hurt[23] 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 with your site’s domain name and path, for example:





Instead of setting baseURL to or, 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


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[25] in the config.yaml.

  tag: tags

This overrides Hugo’s default, which is:

  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


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


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.

More information about hosting and deployment is at

19. Possible next steps

19.2. Learn about Hugo bundles

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 and⁠[33] 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.


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.⁠


See also


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. cmd.exe is also known as CMD and is pronounced “cee em dee.” It’s also sometimes referred to as “Command Prompt” (which is a completely ambiguous name IMHO). Details are at Wikipedia’s cmd.exe.
4. If you use a “sync app,” such as Dropbox or, you may want to put your Hugo directory somewhere below ~/Dropbox or ~/Sync. To learn about these type of apps and services, see
5. Using tilde (~) as a shortcut for the home directory works in PowerShell and nix-based shells, but does not work in cmd.exe.
6. Hugo layout files, which are also called templates, are written in Go HTML.
7. 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 ¯∖_(ツ)_/¯).
8. To install or update extended hugo.exe on Windows with the Scoop package manager, first run scoop update (which updates the Scoop app manifests) and then run either scoop install hugo-extended or scoop update hugo-extended. Details about Scoop’s current hugo-extended version are at…/hugo-extended.json.
9. The command sudo dpkg --install ./hugo_extended_0.88.1_Linux-64bit.deb will work if you invoke it from the directory that the .deb is in. Since hugo has no dependencies, there should be no issues installing it with dpkg --install. (This is how I install hugo on WSL, which is also known as “Windows’ Subsystem for Linux” and “Bash on Ubuntu on Windows.”)
10. “Binary” is another word for executable.
11. 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.
12. A nice introduction to pipelines is Jessie Frazelle’s For the Love of Pipes.
13. Windows has many command-line shells, including cmd.exe, PowerShell, WSL Bash, and Git Bash.
14. The more command is not included in Git Bash, but the less command, which can do everything more can do (and more), is.
15. TGIH (for Themeless & Gitless Introduction to Hugo) will be the “working directory” for the rest of this tutorial.
16. 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.
17. 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’s Hyphen-minus.
18. 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.
19. If you want to use upper-case characters in a web page URL, put disablePathToLower: true in your config.yaml.
20. Actually bundle directory names are also used as part of a web page URL, but the TGIH website does not use content bundles.
21. HTML comments will be removed from the built HTML pages if you build with hugo --minify.
22. 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
23. Double slashes in a path will be interpreted as one slash so, for example, is interpreted as
24. The plural of “emoji” can be spelled “emoji” or “emojis.” To learn about pluralizing the word “emoji,” see’s definition of emoji and the second Q in’s FAQ. Also see Infinite Ink’s #emoji Portal.
25. A nested map is also known as an associative array, a dictionary, a dict, a hash table, a hash, a map, a mapping, a named map, an object, or a table. For more about this data-serialization object, see Infinite Ink’s YAML Includes Atoms, Maps, and Lists (Featuring the String ¯∖_(ツ)_/¯).
26. 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, Shortcodes, and Fragments in Fragment 18.
27. In Hugo markdownify means convert Markdown to HTML
28. .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.
29. 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.
30. 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.
31. 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 👍 👎 📝

Please comment so I know I'm not speaking into the void. Also, your public comment might improve this page or help me to improve this page.