Introduction
Sensible defaults
Hugo offers many configuration options, but its defaults are often sufficient. A new site requires only these settings:
baseURL: https://example.org/
languageCode: en-us
title: My New Hugo Site
baseURL = 'https://example.org/'
languageCode = 'en-us'
title = 'My New Hugo Site'
{
"baseURL": "https://example.org/",
"languageCode": "en-us",
"title": "My New Hugo Site"
}
Only define settings that deviate from the defaults. A smaller configuration file is easier to read, understand, and debug. Keep your configuration concise.
The best configuration file is a short configuration file.
Configuration file
Create a site configuration file in the root of your project directory, naming it hugo.toml
, hugo.yaml
, or hugo.json
, with that order of precedence.
my-project/
└── hugo.toml
For versions v0.109.0 and earlier, the site configuration file was named config
. While you can still use this name, it’s recommended to switch to the newer naming convention, hugo
.
A simple example:
baseURL: https://example.org/
languageCode: en-us
params:
contact:
email: info@example.org
phone: +1 202-555-1212
subtitle: The Best Widgets on Earth
title: ABC Widgets, Inc.
baseURL = 'https://example.org/'
languageCode = 'en-us'
title = 'ABC Widgets, Inc.'
[params]
subtitle = 'The Best Widgets on Earth'
[params.contact]
email = 'info@example.org'
phone = '+1 202-555-1212'
{
"baseURL": "https://example.org/",
"languageCode": "en-us",
"params": {
"contact": {
"email": "info@example.org",
"phone": "+1 202-555-1212"
},
"subtitle": "The Best Widgets on Earth"
},
"title": "ABC Widgets, Inc."
}
To use a different configuration file when building your site, use the --config
flag:
hugo --config other.toml
Combine two or more configuration files, with left-to-right precedence:
hugo --config a.toml,b.yaml,c.json
Configuration directory
Instead of a single site configuration file, split your configuration by environment, root configuration key, and language. For example:
my-project/
└── config/
├── _default/
│ ├── hugo.toml
│ ├── menus.en.toml
│ ├── menus.de.toml
│ └── params.toml
└── production/
└── params.toml
The root configuration keys are build
, caches
, cascade
, deployment
, imaging
, languages
, markup
, menus
, minify
, module
, outputs
, page
, pagination
, params
, permalinks
, privacy
, security
, segments
, server
, services
, sitemap
, and taxonomies
.
Omit the root key
When splitting the configuration by root key, omit the root key in the component file. For example, these are equivalent:
params:
foo: bar
[params]
foo = 'bar'
{
"params": {
"foo": "bar"
}
}
foo: bar
foo = 'bar'
{
"foo": "bar"
}
Recursive parsing
Hugo parses the config
directory recursively, allowing you to organize the files into subdirectories. For example:
my-project/
└── config/
└── _default/
├── navigation/
│ ├── menus.de.toml
│ └── menus.en.toml
└── hugo.toml
Example
my-project/
└── config/
├── _default/
│ ├── hugo.toml
│ ├── menus.en.toml
│ ├── menus.de.toml
│ └── params.toml
├── production/
│ ├── hugo.toml
│ └── params.toml
└── staging/
├── hugo.toml
└── params.toml
Considering the structure above, when running hugo --environment staging
, Hugo will use every setting from config/_default
and merge staging
’s on top of those.
Let’s take an example to understand this better. Let’s say you are using Google Analytics for your website. This requires you to specify a Google tag ID in your site configuration:
services:
googleAnalytics:
ID: G-XXXXXXXXX
[services]
[services.googleAnalytics]
ID = 'G-XXXXXXXXX'
{
"services": {
"googleAnalytics": {
"ID": "G-XXXXXXXXX"
}
}
}
Now consider the following scenario:
- You don’t want to load the analytics code when running
hugo server
. - You want to use different Google tag IDs for your production and staging environments. For example:
G-PPPPPPPPP
for productionG-SSSSSSSSS
for staging
To satisfy these requirements, configure your site as follows:
config/_default/hugo.toml
- Exclude the
services.googleAnalytics
section. This will prevent loading of the analytics code when you runhugo server
. - By default, Hugo sets its
environment
todevelopment
when runninghugo server
. In the absence of aconfig/development
directory, Hugo uses theconfig/_default
directory.
- Exclude the
config/production/hugo.toml
Include this section only:
services: googleAnalytics: ID: G-PPPPPPPPP
[services] [services.googleAnalytics] ID = 'G-PPPPPPPPP'
{ "services": { "googleAnalytics": { "ID": "G-PPPPPPPPP" } } }
You do not need to include other parameters in this file. Include only those parameters that are specific to your production environment. Hugo will merge these parameters with the default configuration.
By default, Hugo sets its
environment
toproduction
when runninghugo
. The analytics code will use theG-PPPPPPPPP
tag ID.
config/staging/hugo.toml
Include this section only:
services: googleAnalytics: ID: G-SSSSSSSSS
[services] [services.googleAnalytics] ID = 'G-SSSSSSSSS'
{ "services": { "googleAnalytics": { "ID": "G-SSSSSSSSS" } } }
You do not need to include other parameters in this file. Include only those parameters that are specific to your staging environment. Hugo will merge these parameters with the default configuration.
To build your staging site, run
hugo --environment staging
. The analytics code will use theG-SSSSSSSSS
tag ID.
Merge configuration settings
Hugo merges configuration settings from themes and modules, prioritizing the project’s own settings. Given this simplified project structure with two themes:
project/
├── themes/
│ ├── theme-a/
│ │ └── hugo.toml
│ └── theme-b/
│ └── hugo.toml
└── hugo.toml
and this project-level configuration:
baseURL: https://example.org/
languageCode: en-us
theme:
- theme-a
- theme-b
title: My New Hugo Site
baseURL = 'https://example.org/'
languageCode = 'en-us'
theme = ['theme-a', 'theme-b']
title = 'My New Hugo Site'
{
"baseURL": "https://example.org/",
"languageCode": "en-us",
"theme": [
"theme-a",
"theme-b"
],
"title": "My New Hugo Site"
}
Hugo merges settings in this order:
- Project configuration (
hugo.toml
in the project root) theme-a
configurationtheme-b
configuration
The _merge
setting within each top-level configuration key controls which settings are merged and how they are merged.
The value for _merge
can be one of:
- none
- No merge.
- shallow
- Only add values for new keys.
- deep
- Add values for new keys, merge existing.
Note that you don’t need to be so verbose as in the default setup below; a _merge
value higher up will be inherited if not set.
build:
_merge: none
caches:
_merge: none
cascade:
_merge: none
contenttypes:
_merge: none
deployment:
_merge: none
frontmatter:
_merge: none
httpcache:
_merge: none
imaging:
_merge: none
languages:
_merge: none
en:
_merge: none
menus:
_merge: shallow
params:
_merge: deep
markup:
_merge: none
mediatypes:
_merge: shallow
menus:
_merge: shallow
minify:
_merge: none
module:
_merge: none
outputformats:
_merge: shallow
outputs:
_merge: none
page:
_merge: none
pagination:
_merge: none
params:
_merge: deep
permalinks:
_merge: none
privacy:
_merge: none
related:
_merge: none
security:
_merge: none
segments:
_merge: none
server:
_merge: none
services:
_merge: none
sitemap:
_merge: none
taxonomies:
_merge: none
[build]
_merge = 'none'
[caches]
_merge = 'none'
[cascade]
_merge = 'none'
[contenttypes]
_merge = 'none'
[deployment]
_merge = 'none'
[frontmatter]
_merge = 'none'
[httpcache]
_merge = 'none'
[imaging]
_merge = 'none'
[languages]
_merge = 'none'
[languages.en]
_merge = 'none'
[languages.en.menus]
_merge = 'shallow'
[languages.en.params]
_merge = 'deep'
[markup]
_merge = 'none'
[mediatypes]
_merge = 'shallow'
[menus]
_merge = 'shallow'
[minify]
_merge = 'none'
[module]
_merge = 'none'
[outputformats]
_merge = 'shallow'
[outputs]
_merge = 'none'
[page]
_merge = 'none'
[pagination]
_merge = 'none'
[params]
_merge = 'deep'
[permalinks]
_merge = 'none'
[privacy]
_merge = 'none'
[related]
_merge = 'none'
[security]
_merge = 'none'
[segments]
_merge = 'none'
[server]
_merge = 'none'
[services]
_merge = 'none'
[sitemap]
_merge = 'none'
[taxonomies]
_merge = 'none'
{
"build": {
"_merge": "none"
},
"caches": {
"_merge": "none"
},
"cascade": {
"_merge": "none"
},
"contenttypes": {
"_merge": "none"
},
"deployment": {
"_merge": "none"
},
"frontmatter": {
"_merge": "none"
},
"httpcache": {
"_merge": "none"
},
"imaging": {
"_merge": "none"
},
"languages": {
"_merge": "none",
"en": {
"_merge": "none",
"menus": {
"_merge": "shallow"
},
"params": {
"_merge": "deep"
}
}
},
"markup": {
"_merge": "none"
},
"mediatypes": {
"_merge": "shallow"
},
"menus": {
"_merge": "shallow"
},
"minify": {
"_merge": "none"
},
"module": {
"_merge": "none"
},
"outputformats": {
"_merge": "shallow"
},
"outputs": {
"_merge": "none"
},
"page": {
"_merge": "none"
},
"pagination": {
"_merge": "none"
},
"params": {
"_merge": "deep"
},
"permalinks": {
"_merge": "none"
},
"privacy": {
"_merge": "none"
},
"related": {
"_merge": "none"
},
"security": {
"_merge": "none"
},
"segments": {
"_merge": "none"
},
"server": {
"_merge": "none"
},
"services": {
"_merge": "none"
},
"sitemap": {
"_merge": "none"
},
"taxonomies": {
"_merge": "none"
}
}
Environment variables
You can also configure settings using operating system environment variables:
export HUGO_BASEURL=https://example.org/
export HUGO_ENABLEGITINFO=true
export HUGO_ENVIRONMENT=staging
hugo
The above sets the baseURL
, enableGitInfo
, and environment
configuration options and then builds your site.
An environment variable takes precedence over the values set in the configuration file. This means that if you set a configuration value with both an environment variable and in the configuration file, the value in the environment variable will be used.
Environment variables simplify configuration for CI/CD deployments like GitHub Pages, GitLab Pages, and Netlify by allowing you to set values directly within their respective configuration and workflow files.
Environment variable names must be prefixed with HUGO_
.
To set custom site parameters, prefix the name with HUGO_PARAMS_
.
For snake_case variable names, the standard HUGO_
prefix won’t work. Hugo infers the delimiter from the first character following HUGO
. This allows for variations like HUGOxPARAMSxAPI_KEY=abcdefgh
using any permitted delimiter.
In addition to configuring standard settings, environment variables may be used to override default values for certain internal settings:
- DART_SASS_BINARY
- (
string
) The absolute path to the Dart Sass executable. By default, Hugo searches for the executable in each of the paths in thePATH
environment variable. - HUGO_FILE_LOG_FORMAT
- (
string
) A format string for the file path, line number, and column number displayed when reporting errors, or when calling thePosition
method from a shortcode or Markdown render hook. Valid tokens are:file
,:line
, and:col
. Default is:file::line::col
. - HUGO_MEMORYLIMIT
- New in v0.123.0
- (
int
) The maximum amount of system memory, in gigabytes, that Hugo can use while rendering your site. Default is 25% of total system memory. - HUGO_NUMWORKERMULTIPLIER
- (
int
) The number of workers used in parallel processing. Default is the number of logical CPUs.
Current configuration
Display the complete site configuration with:
hugo config
Display a specific configuration setting with:
hugo config | grep [key]
Display the configured file mounts with:
hugo config mounts