Notes on Customizing Hugo Blogs
I built this blog using Hugo, a static site generator written in Go. If you’re building your own blog, you’ll naturally want to customize the design to your liking. So I’ve documented what I learned about Hugo’s basic structure as a memo. It might look a bit complex at first, but once you get used to it, it’s actually quite simple.
Note that at the time of writing this article, I’m using Hugo v0.148.0.
Basic Directory Structure of Hugo
In Hugo, all articles (md files) are stored in the content/
directory. This directory serves as the starting point for all content on your site. The most basic structure looks like this:
<Project Root>
├── content/ # All articles
├── themes/<theme-name>/layouts # Templates provided by the theme
├── layouts/ # Custom templates to override the theme
├── public/ # Built site output
In the generated site, the directory structure under content/
directly becomes the URL structure of your site. For example, content/posts/article.md
can be accessed at the URL /posts/article/
.
Hugo generates pages for individual articles (.md files) or directories. In other words, you can place .md files, or for directories, place an _index.md
file to generate a page for the corresponding URL.
About Themes
Templates are used when converting articles and directories into pages. Templates are basically provided by themes. If you’re satisfied with the design and functionality provided by the theme, you don’t need to do anything. However, if you want to change the design of specific pages or add new functionality, you need to customize templates.
While it’s possible to directly edit templates within the theme, it’s better to create custom templates and implement only the differences. To use custom templates, simply create a layouts
directory directly under the project root and place templates there. This allows you to override theme templates precisely.
Adopting this differential implementation approach makes it easy to keep up with theme updates (though you can directly update the theme if you don’t care about staying current).
Template Selection Rules
Hugo automatically selects templates based on the type of page. Initially, I was enthusiastic about perfectly explaining template selection rules in this article, but it turned out to be more difficult to write than I thought, so I quickly gave up. Here I’ll only explain the basic rules. For details, please refer to the official documentation. For building simple sites like this blog, the knowledge written here should be sufficient.
Templates basically have their filenames determined by specification according to template type, and you can’t assign arbitrary names (strictly speaking, directories directly under content
are called “sections” and section templates can have template files with the same name as the section name, but I won’t cover that here. You probably don’t need to know this for blog construction. Maybe).
This blog uses the following templates:
index.html
: Site’s top pagelist.html
: Article list pagessingle.html
: Individual article pagesterms.html
: Taxonomy list pagesbaseof.html
: Common template
※Taxonomy is an important feature, so I’ll explain it later
For example, when generating article list pages, list.html
is used, but:
- Search for
list.html
in custom templates and use it if found - If not found, search for
list.html
in theme templates and use it if found
This is a two-step process for template searching. Each step follows rules for searching, but since I’ve decided to omit section explanations on this page, you can think of it as searching with the following rules:
- Search for
list.html
- Search for
_default/list.html
Note that to generate list pages using list.html
, you need to place _index.md
in the directory (as already mentioned), but for section directories, list pages using list.html
are automatically generated even without placing _index.md
.
Article Classification with Taxonomies
Hugo has a mechanism called Taxonomy for classifying and organizing articles (a system for easily implementing article classification using tags and categories common in blogs). To use taxonomies, you first need to define what classifications to use in the configuration file (hugo.toml
).
[taxonomies]
tag = 'tags'
category = 'categories'
Specify the key name used in frontmatter on the left side of =, and the value that becomes the URL path on the right side. In article frontmatter, you specify classifications like this:
---
tags: ["hugo", "blog"]
categories: ["tech"]
---
Then, Hugo automatically generates the following pages:
/tags/
- List of all tags (usesterms.html
)/tags/hugo/
- List of articles with “hugo” tag (useslist.html
)/tags/blog/
- List of articles with “blog” tag (useslist.html
)/categories/
- List of all categories (usesterms.html
)/categories/tech/
- List of articles in “tech” category (useslist.html
)
What’s interesting is that you can generate each list page using only the generic list.html
without creating separate list.html
for tag lists and list.html
for category lists. However, there are cases where you want to apply independent designs to specific list pages. For example, if you want to create a custom design only for tag list pages, you can create a template at the following path:
layouts/tags/list.html
This allows you to generate only tag list pages with a custom design.
To briefly explain how generic list.html
generates individual list pages, Hugo achieves this by setting up a list of articles with specific tags or categories in the template variable .Pages
before starting the build process.
Common Layout with baseof Template
The template that is commonly called by all pages is layouts/_default/baseof.html
. This is like a Layout component in React, where you can define the common layout for the entire site, such as headers and footers, in one place.
Looking inside baseof.html
, you’ll find descriptions like this:
<main>{{ block "main" . }}{{ end }}</main>
This {{ block "main" . }}{{ end }}
is a slot for inserting content specific to each page, declaring that it uses main as the slot name. And for example, looking at the top page template index.html
:
{{ define "main" }}
...Top page content...
{{ end }}
This way, the top page content is given the name main
. This is how the top page content gets inserted into the baseof.html
slot.
Reusing Components with partials
Templates have another useful feature. There’s a mechanism called partial
for extracting commonly reusable templates.
{{ partial "head.html" . }}
Like this, you can reuse common components such as headers and footers in multiple places. This eliminates code duplication and improves maintainability. As a side note, the .
that appears in the code introduced so far is notation for passing page context to templates. With this, you can access information like page titles, creation dates, and frontmatter information within templates.
Shortcode
Hugo has a useful feature called shortcodes. This is a convenient mechanism for easily embedding complex content that’s difficult to express with markdown notation alone. While templates are components for designers to use, shortcodes are common components for article writers to use.
For example, to embed a YouTube video:
{{< youtube "video-id" >}}
To insert figures:
{{< figure src="image.jpg" title="Figure title" >}}
You can create your own shortcodes by placing template files in the layouts/shortcodes/
directory. For example, if you create layouts/shortcodes/note.html
:
{{< note >}}
Note content here
{{< /note >}}
You can use it like this (Hugo also provides built-in shortcodes for YouTube, X, Instagram, etc.).
Conclusion
I’ve summarized the basic structure of Hugo and templates, covering the knowledge needed to actually build a blog. I didn’t go into detail about template syntax, but I think you can look that up when you actually have specific areas you want to customize. It’s good to start by copying theme templates and trying various changes.
By the way, Hugo templates don’t use Hugo-specific syntax but rather Go language’s standard template syntax. However, you don’t need Go language knowledge to create templates, so don’t worry. The template syntax itself is simple, and you can customize sufficiently by learning HTML and a little variable notation.
Well, that’s about it. Good luck with building your Hugo blog.