Specifying URL Path Segments in Hugo
Updated 2021-September-15

Page contents

News

2021-September-1  Published this evolving⁠[1] article.

 

Prerequisites

This article assumes…

 

URL paths in Hugo

Default URL paths

By default, a Hugo-generated web page’s URL path closely matches the path of its primary source file. For example, the hugo command transforms this Infinite Ink source file:

ROOT/content/meta/about/index.adoc

to this destination file:

ROOT/public/meta/about/index.html

When this destination file is put on the Infinite Ink web server, the URL is:

 

For more about this, see Infinite Ink’s…

 

Overriding default URL paths

To override Hugo’s default URL paths, you can…

  • specify Permalinks patterns in a Hugo config file

  • and/or use one or more of these keys in the front matter of a page’s primary source file:

    • url

    • slug

    • aliases

To learn about this, see gohugo.io/content-management/urls/.

 

Below I give examples of using Permalinks to specify non-⁠default URLs.

 

This page’s source file, destination file, and URL

This page’s source and destination files

The source file of this page is:

ROOT/content/articles/hugo-urls/nested/sections/index.adoc
             ^^^^^^^^
               Note

And the destination file is:

ROOT/public/hugo-urls/nested/sections/index.html

 

This page’s URL and some URL terminology

The URL of this page is:

https://www.ii.com/hugo-urls/nested/sections/

The scheme is:

https

The hostname (also known as domain name) is:

www.ii.com

The path is:

/hugo-urls/nested/sections/

Each of the following is a path segment:

hugo-urls
nested
sections

The last part of this URL path, sections, is sometimes called the slug.

 

To learn more about URL terminology, see wikipedia.org/wiki/URL.

 

Learn to specify URL path segments by example

Example 1: Remove articles path segment from this page’s URL

Since I do not want the string articles to be in the URL of this page (or any page in the content/articles/ directory), I do the following three steps.

 

A. Make all but the last content directory a branch bundle

Here is the part of Infinite Ink’s directory structure that is relevant to this page’s source file.

.
└── content
    ├── _index.md
    └── articles
        ├── _index.md
        └── hugo-urls
            ├── _index.md
            └── nested
                ├── _index.md
                └── sections
                    └── index.adoc

Note:

  • The four directories content, articles, hugo-urls, and nested are each a branch bundle.

  • The three directories articles, hugo-urls, and nested are each a section.

  • articles is sometimes called the root section.

  • The last directory, sections, is a leaf bundle and is not a section.

  • The file extensions .md and .adoc can be any of the content file extensions known to Hugo.

  • The content of each of the four _index.md files can be as simple as this:

---
# Important: Front matter is required.
# Because of this _index.md file, this directory is a branch bundle.
---

 

Infinite Ink’s config.yaml includes this:

Permalinks:
  articles: /:sections[1:]/:slug/
                      ^^^^
                      slice syntax

 

To use the above slice syntax, you need to be using Hugo v0.83.0⁠[2] or newer.

 

C. Use the hugo command to build the website

With the above structure and settings, the hugo command generates this destination file:

ROOT/public/hugo-urls/nested/sections/index.html

 

 

Example 2: Change products/shirts to p/shirts in Simone’s website

On 2021-August-29, Simone posted about Folder hierarchy in permalink in stackoverflow.com’s Hugo tag. Here is an excerpt of his question:

⋮
I want to have URLs like:

  • content/products/shirts/very-beautiful-shirt.md => /p/shirts/very-beautiful-shirt
⋮

From what he wrote, it seems his content/ directory includes this:

.
└── content
    └── products
        ├── shirts
        │   ├── simple.md
        │   └── very-beautiful-shirt.md
        └── hats
            └── simple.md

And he wants the hugo command to generate this in the public/ directory:

.
└── public
    └── p
        ├── shirts
        │   ├── simple
        │   │   └── index.html
        │   └── very-beautiful-shirt
        │       └── index.html
        └── hats
            └── simple
                └── index.html

 

Steps A, B, and C below should do this.

 

A. Use bundles everywhere

To get the URLs that Simone wants, it seems (based on my experiments) that each directory on the path must be a bundle. Here is the structure that works for me:

.
└── content
    ├── _index.md
    └── products
        ├── _index.md
        ├── shirts
        │   ├── _index.md
        │   ├── simple
        │   │   └── index.md
        │   └── very-beautiful-shirt
        │       └── index.md
        └── hats
            ├── _index.md
            └── simple
                └── index.md

 

Specify this in a config.yaml:

Permalinks:
  products: /p/:sections[1:]/:filename/
                        ^^^^
                        slice syntax

 

Or this in a config.toml:

[permalinks]
  products = '/p/:sections[1:]/:filename/'
                          ^^^^
                          slice syntax

 

C. Use the hugo command to build the website

With the above structure and settings, the hugo command generates the destination files and URLs that Simone wants.

 

About slices

:sections slice syntax

Sections slice syntax, such as :sections[1:] used above, was introduced in Hugo v0.83.0.⁠[2] Here are some examples that help to explain the meaning of this syntax.

Syntax Zero-⁠Based
Section(s)
Example if sections are
articles/hugo-⁠urls/nested

:sections[0]

0

articles

:sections[1]

1

hugo-urls

:sections[2]

2

nested

:sections[last]

(last)

nested

:sections[1:3]

1,2

hugo-urls/nested

:sections[:3]

0,1,2

articles/hugo-⁠urls/nested

:sections[:2]

0,1

articles/hugo-urls

:sections[:last]

0,1,…,(last-1)

articles/hugo-urls

:sections[1:]

1,2,…,(last)

hugo-urls/nested

 

Thanks to the following for some of the above examples.

 

  • :sections[0] is sometimes called the root section.

  • :sections (without slice syntax) means “all sections.”

 

About Go slice expressions

To learn about Go slice expressions, see golang.org/ref/spec#Slice_expressions

 

See also

Endnotes


1. Many Infinite Ink articles, including this one, are evergreen and regularly updated.
2. Hugo v0.83.0 was released 2021-May-1.⁠💐

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.