Configure permalinks
This is the default configuration:
permalinks:
page: {}
section: {}
taxonomy: {}
term: {}
[permalinks]
[permalinks.page]
[permalinks.section]
[permalinks.taxonomy]
[permalinks.term]
{
"permalinks": {
"page": {},
"section": {},
"taxonomy": {},
"term": {}
}
}
Define a URL pattern for each top-level section. Each URL pattern can target a given language and/or page kind.
The url
front matter field overrides any matching permalink pattern.
Monolingual example
With this content structure:
content/
├── posts/
│ ├── bash-in-slow-motion.md
│ └── tls-in-a-nutshell.md
├── tutorials/
│ ├── git-for-beginners.md
│ └── javascript-bundling-with-hugo.md
└── _index.md
Render tutorials under “training”, and render the posts under “articles” with a date-base hierarchy:
permalinks:
page:
posts: /articles/:year/:month/:slug/
tutorials: /training/:slug/
section:
posts: /articles/
tutorials: /training/
[permalinks]
[permalinks.page]
posts = '/articles/:year/:month/:slug/'
tutorials = '/training/:slug/'
[permalinks.section]
posts = '/articles/'
tutorials = '/training/'
{
"permalinks": {
"page": {
"posts": "/articles/:year/:month/:slug/",
"tutorials": "/training/:slug/"
},
"section": {
"posts": "/articles/",
"tutorials": "/training/"
}
}
}
The structure of the published site will be:
public/
├── articles/
│ ├── 2023/
│ │ ├── 04/
│ │ │ └── bash-in-slow-motion/
│ │ │ └── index.html
│ │ └── 06/
│ │ └── tls-in-a-nutshell/
│ │ └── index.html
│ └── index.html
├── training/
│ ├── git-for-beginners/
│ │ └── index.html
│ ├── javascript-bundling-with-hugo/
│ │ └── index.html
│ └── index.html
└── index.html
To create a date-based hierarchy for regular pages in the content root:
permalinks:
page:
/: /:year/:month/:slug/
[permalinks]
[permalinks.page]
'/' = '/:year/:month/:slug/'
{
"permalinks": {
"page": {
"/": "/:year/:month/:slug/"
}
}
}
Use the same approach with taxonomy terms. For example, to omit the taxonomy segment of the URL:
permalinks:
term:
tags: /:slug/
[permalinks]
[permalinks.term]
tags = '/:slug/'
{
"permalinks": {
"term": {
"tags": "/:slug/"
}
}
}
Multilingual example
Use the permalinks
configuration as a component of your localization strategy.
With this content structure:
content/
├── en/
│ ├── books/
│ │ ├── les-miserables.md
│ │ └── the-hunchback-of-notre-dame.md
│ └── _index.md
└── es/
├── books/
│ ├── les-miserables.md
│ └── the-hunchback-of-notre-dame.md
└── _index.md
And this site configuration:
defaultContentLanguage: en
defaultContentLanguageInSubdir: true
languages:
en:
contentDir: content/en
languageCode: en-US
languageDirection: ltr
languageName: English
permalinks:
page:
books: /books/:slug/
section:
books: /books/
weight: 1
es:
contentDir: content/es
languageCode: es-ES
languageDirection: ltr
languageName: Español
permalinks:
page:
books: /libros/:slug/
section:
books: /libros/
weight: 2
defaultContentLanguage = 'en'
defaultContentLanguageInSubdir = true
[languages]
[languages.en]
contentDir = 'content/en'
languageCode = 'en-US'
languageDirection = 'ltr'
languageName = 'English'
weight = 1
[languages.en.permalinks]
[languages.en.permalinks.page]
books = '/books/:slug/'
[languages.en.permalinks.section]
books = '/books/'
[languages.es]
contentDir = 'content/es'
languageCode = 'es-ES'
languageDirection = 'ltr'
languageName = 'Español'
weight = 2
[languages.es.permalinks]
[languages.es.permalinks.page]
books = '/libros/:slug/'
[languages.es.permalinks.section]
books = '/libros/'
{
"defaultContentLanguage": "en",
"defaultContentLanguageInSubdir": true,
"languages": {
"en": {
"contentDir": "content/en",
"languageCode": "en-US",
"languageDirection": "ltr",
"languageName": "English",
"permalinks": {
"page": {
"books": "/books/:slug/"
},
"section": {
"books": "/books/"
}
},
"weight": 1
},
"es": {
"contentDir": "content/es",
"languageCode": "es-ES",
"languageDirection": "ltr",
"languageName": "Español",
"permalinks": {
"page": {
"books": "/libros/:slug/"
},
"section": {
"books": "/libros/"
}
},
"weight": 2
}
}
}
The structure of the published site will be:
public/
├── en/
│ ├── books/
│ │ ├── les-miserables/
│ │ │ └── index.html
│ │ ├── the-hunchback-of-notre-dame/
│ │ │ └── index.html
│ │ └── index.html
│ └── index.html
├── es/
│ ├── libros/
│ │ ├── les-miserables/
│ │ │ └── index.html
│ │ ├── the-hunchback-of-notre-dame/
│ │ │ └── index.html
│ │ └── index.html
│ └── index.html
└── index.html
Tokens
Use these tokens when defining a URL pattern.
:year
- The 4-digit year as defined in the front matter
date
field. :month
- The 2-digit month as defined in the front matter
date
field. :monthname
- The name of the month as defined in the front matter
date
field. :day
- The 2-digit day as defined in the front matter
date
field. :weekday
- The 1-digit day of the week as defined in the front matter
date
field (Sunday =0
). :weekdayname
- The name of the day of the week as defined in the front matter
date
field. :yearday
- The 1- to 3-digit day of the year as defined in the front matter
date
field. :section
- The content’s section.
:sections
- The content’s sections hierarchy. You can use a selection of the sections using slice syntax:
:sections[1:]
includes all but the first,:sections[:last]
includes all but the last,:sections[last]
includes only the last,:sections[1:2]
includes section 2 and 3. Note that this slice access will not throw any out-of-bounds errors, so you don’t have to be exact. :title
- The
title
as defined in front matter, else the automatic title. Hugo generates titles automatically for section, taxonomy, and term pages that are not backed by a file. :slug
- The
slug
as defined in front matter, else thetitle
as defined in front matter, else the automatic title. Hugo generates titles automatically for section, taxonomy, and term pages that are not backed by a file. :filename
- The content’s file name without extension, applicable to the
page
page kind.Deprecated in v0.144.0
The
:filename
token has been deprecated. Use:contentbasename
instead. :slugorfilename
- The
slug
as defined in front matter, else the content’s file name without extension, applicable to thepage
page kind.Deprecated in v0.144.0
The
:slugorfilename
token has been deprecated. Use:slugorcontentbasename
instead. :contentbasename
- New in v0.144.0
- The content base name.
:slugorcontentbasename
- New in v0.144.0
- The
slug
as defined in front matter, else the content base name.
For time-related values, you can also use the layout string components defined in Go’s time package. For example:
permalinks:
posts: /:06/:1/:2/:title/
[permalinks]
posts = '/:06/:1/:2/:title/'
{
"permalinks": {
"posts": "/:06/:1/:2/:title/"
}
}