When I was updating the tutorial, I thought about adding an overview of themes because of some chatter on this forum. Entry level users seem to get confused about “layouts” versus “themes.” My take is that the notion that it is a “layout” if it’s not in the “themes” directory contributes, so it’s an unnecessary distinction. The distinction that’s important is that these “layout” files override the corresponding “themes” files.
I used “default” in the article below. It doesn’t ring quite true, though. So, I’m asking for your opinion - is there a better way to describe it? (Assuming that you’re looking at this from that same entry-level perspective.)
The Anatomy of a Theme
Hugo themes are built around a standard directory structure. Hugo relies on that structure to determine what to do with your content.
Every theme has archetypes/
, layout/
, and static/
directories. Some themes may also have data/
.
-
archetypes/
contains files that are used by thehugo new
command to help create content files. -
layouts/
contains the template files that Hugo uses to build your HTML files from your content files. -
static/
contains CSS, JavaScript, and other files that are copied into your web site. Static files are not changed in any way by Hugo. -
data/
contains files that the user updates to supply information to a theme.
There are two types of themes: the “default” theme and named themes. The difference is that named themes are placed in a sub-directory of the site, themes/nameOfTheme
, while the “default” theme is placed in the site’s root directory.
The Default Hugo Theme
Hugo has no opinion on what your web site should look like or what content it should contain, so when you use the hugo new site
command to create a new site, it creates an empty (and unamed theme) in the site’s root directory:
$ hugo new site hugo-0.16
$ find hugo-0.16 | xargs ls -ld
drwxr-xr-x 8 mdhender wheel 272 Nov 27 11:39 hugo-0.16
drwxr-xr-x 2 mdhender wheel 68 Nov 27 11:39 hugo-0.16/archetypes
-rw-r--r-- 1 mdhender wheel 107 Nov 27 11:39 hugo-0.16/config.toml
drwxr-xr-x 2 mdhender wheel 68 Nov 27 11:39 hugo-0.16/content
drwxr-xr-x 2 mdhender wheel 68 Nov 27 11:39 hugo-0.16/data
drwxr-xr-x 2 mdhender wheel 68 Nov 27 11:39 hugo-0.16/layouts
drwxr-xr-x 2 mdhender wheel 68 Nov 27 11:39 hugo-0.16/static
$
This theme, the one we’re calling the “default” theme, is special because Hugo always looks there first to find files when rendering your web site.
You’ll notice that the “default” theme doesn’t include any files (the config.toml
is part of the site, not the theme). There are no files, so there are no rules, and no output in your public/
directory when you render your site. That leads to the saying “Hugo doesn’t have a default theme.” It’s confusing at first but it should make sense by the time we’re done.
These directories, since they’re searched first, provide an easy way for end-users to override parts of a named theme. For example, if a named theme provides a template that set the heading level to 1 for articles, the user could copy that file from the named theme into these directories and change the H1 to H2. When Hugo next runs, it would find the file in the “default” theme and use it to create the site.
On the surface, that seems like odd behavior, but it’s actually a very good thing. It allows users to easily customize your theme without changing any of the files in your theme. That makes it very easy for them to update their sites when you release an upgrade to your theme since their changes are completely outside of your theme.
Named Themes
Named themes are created with the hugo new theme
command. By default, they’re created as sub-directories of the themes/
directory in your site’s root directory. (Don’t worry, Hugo will create the themes/
directory if needed.)
# show the directories created by the new site command
$ find hugo-0.16 -type d
hugo-0.16
hugo-0.16/archetypes
hugo-0.16/content
hugo-0.16/data
hugo-0.16/layouts
hugo-0.16/static
# create a new theme named "zafta"
$ cd hugo-0.16
$ hugo new theme zafta
$ cd ..
# show the directories created by the new theme command
$ find hugo-0.16 -type d
hugo-0.16
hugo-0.16/archetypes
hugo-0.16/content
hugo-0.16/data
hugo-0.16/layouts
hugo-0.16/static
hugo-0.16/themes
hugo-0.16/themes/zafta
hugo-0.16/themes/zafta/archetypes
hugo-0.16/themes/zafta/layouts
hugo-0.16/themes/zafta/layouts/_default
hugo-0.16/themes/zafta/layouts/partials
hugo-0.16/themes/zafta/static
hugo-0.16/themes/zafta/static/css
hugo-0.16/themes/zafta/static/js
$
Hugo created themes/zafta/
for us, then added the archetypes/
, layouts/
, and static/
directories for us. That’s exactly the same structure as for the “default” theme.
Hugo also created quite a few files for our theme:
$ cd hugo-0.16/themes/
$ find zafta | xargs ls -1d
zafta
zafta/LICENSE.md
zafta/archetypes
zafta/archetypes/default.md
zafta/layouts
zafta/layouts/404.html
zafta/layouts/_default
zafta/layouts/_default/list.html
zafta/layouts/_default/single.html
zafta/layouts/index.html
zafta/layouts/partials
zafta/layouts/partials/footer.html
zafta/layouts/partials/header.html
zafta/static
zafta/static/css
zafta/static/js
zafta/theme.toml
The important ones are the template files, which end in .html
.
$ find zafta -name '*.html' | xargs ls -l
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/404.html
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/_default/list.html
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/_default/single.html
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/index.html
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/partials/footer.html
-rw-r--r-- 1 mdhender wheel 0 Nov 27 12:06 zafta/layouts/partials/header.html
$
The template files are all empty because Hugo doesn’t have an opinion on what your site should look like. In effect, that new theme acts just like that “default” theme. The main difference is that Hugo created the most commonly used template files as a convenience to you.
Using the Default Theme
Hugo will always check first for files in the “default” theme. ?TODO? There is no way to change this behavior.
Using a Named Theme
Hugo will only use a named theme when told to do so. You can do that on the command line with “--theme=zafta
” or by adding a line to your configuration file ("theme = "zafta"
).