Emacs, scripting and anything text oriented.

Hugo Modules: Importing a Theme

Kaushal Modi

A brief guide on how to install Hugo themes using Hugo Modules.

This is a post in the “Hugo Modules” series.

2022-05-26Hugo Modules: Importing a Theme
2022-02-24Hugo Modules: Getting Started

Hello! You are reading this post because you are probably interested in the Hugo Modules feature and are considering to import a Hugo Module as a theme.

Step 0 for that approach is to make your site repo a Hugo Module. If your site already is, then it would have a go.mod file in the repo root. If you don’t have the go.mod file, check out the previous post Hugo Modules: Getting Started first ‼️

If you don’t have a go.mod file for your site repo, and you still decide to continue with the next steps, don’t complain if you see errors like module “foo” not found; either add it as a Hugo Module or store it in “<your site repo>/themes”.: module does not exist. — speaking from experience 😉.

With that out of the way, here are the next steps ..

1 Clean up the old way of setting a theme #

If you are upgrading your Hugo site to switch from the legacy method of using themes (i.e using the theme variable in the site config  In my posts, you may have seen me use the Site Config term or config.toml – They mean the same thing. ), you need to clean that up.

  1. Remove the theme variable from your site config.
  2. Remove the themes directory, or move it out of your Hugo site repo.
    • If you were cloning a theme developed by someone else in there, you can just remove this directory.
    • If you are maintaining your own theme in that directory, move it out of your site repo and convert it to a Hugo Module.

2 Import the “theme” module #

The theme is quoted in this title, because the concept of a Hugo “theme” is a bit old now (<2022-05-26 Thu>) and that has been superseded with the concept of “modules”.

The main difference between a theme and a generic Hugo Module is that the former will allow you to build your site entirely, while the latter might implement only some modular features like enabling the ATOM feed, or adding a search to your website.

I am mentioning this again for convenience, from the previous post in this series:

A module can be your main project or a smaller module providing one or more of the 7 component types defined in Hugo: static, content, layouts, data, assets, i18n, and archetypes. You can combine modules in any combination you like, and even mount directories from non-Hugo projects, forming a big, virtual union file system.

A theme will need to have the “layout” component. Additionally, it might have the “assets”, “static”, and other components too.

Importing a module as a theme will typically look like this in your site config:

    path = "URL of the theme's git remote *without* the 'https://' part"

The path here would be something like github.com/USER/THEME-REPO-NAME or gitlab.com/USER/THEME-REPO-NAME.

It’s possible to take any Hugo theme git repo and import that as a Hugo Module even if that repo isn’t actually one i.e. doesn’t have a go.mod. But it’s recommended that the theme be a proper Hugo Module so that you have better dependency tracking between your site and the theme.

Quick Example #

Follow these steps if you want to try out how this Hugo Module based theme importing

As a reminder, you need to have Go installed on your system.

  1. Create a temporary directory somewhere and cd to it.
  2. Initialize your site as a Hugo Module: hugo mod init foo (yeah, type that out literally — it will work)
  3. Create a config.toml file with the below content. It imports the hugo-mwe-theme  hugo-mwe-theme is a minimal Hugo theme that I use to quickly try out some new feature in Hugo or to create a minimal working example to reproduce a bug. theme.
        path = "gitlab.com/kaushalmodi/hugo-mwe-theme"
    Code Snippet 1: Example of importing a Hugo module as a theme in config.toml
  4. Create content/hello.md. This step is optional and is only so that your test site as some content.
    title = "Hello"

That’s it! Now run the Hugo server (hugo server) and look at your site running on localhost .. while thinking in disbelief.. just how easy all of this was! 😃.

  • Did you need to manually clone any theme? No
  • Would you need to deal with the .gitmodules file? No

3 hugo mod tidy #

Finally, run hugo mod tidy to clean up the go.mod and update/generate the go.sum file. These files will track the module dependencies for your site.

  • The go.mod contains the direct module dependencies for your site.
  • The go.sum contains the versions and hashes of all the direct and indirect dependencies  Just as you added a theme as a Hugo Module to your site, it’s possible that that theme is depending on other Hugo Modules (like the ones I mentioned earlier: ATOM feeds, search, etc.). for your site.

You would need to commit the go.mod and go.sum1 files if you build and deploy your website on a remote server or a CI/CD system.

If you ran the Quick Example, you will see this (as of <2022-05-26 Thu>) in your go.mod:

module foo

go 1.18

require gitlab.com/kaushalmodi/hugo-mwe-theme v0.1.1 // indirect

.. and this in your go.sum:

gitlab.com/kaushalmodi/hugo-mwe-theme v0.1.1 h1:FyTp43CJRpBfoHyWnwQFx//cipgP6xQ9/uucj+qjj1U=
gitlab.com/kaushalmodi/hugo-mwe-theme v0.1.1/go.mod h1:vvq0r/SfKMbiPbyqL4YottSOkpCkBSosqGRm82aDNrU=

4 Updating the theme #

Here are some common ways to update the theme module going forward:

hugo mod get -uUpdate only the modules that your site directly depends on.
hugo mod get -u ./...Update the modules that your site depends on in a recursive fashion.

Additionally, you might or might not need these, but I am documenting them here for completeness:

hugo mod get -u <module path>Update only the specified module2 to the latest version. Example: hugo mod get -u gitlab.com/kaushalmodi/hugo-mwe-theme
hugo mod get <module path>@<git ref>Update a module to the specified git tag or commit. Example: hugo mod get gitlab.com/kaushalmodi/hugo-mwe-theme@v0.1.1

Dependency Graph #

If you have a theme added as a Hugo Module, which depends on other Hugo Modules, it’s often helpful to know the dependency graph. You can do that by running:

hugo mod graph

For the above Quick Example, you will see just this one line because that theme does not depend on other modules:

foo gitlab.com/kaushalmodi/hugo-mwe-theme@v0.1.1

Building your Hugo site on a server #

Alright, so you are able to build your site locally after switching to using themes as modules, great!

Now, if you build and deploy your site on a remote server like Netlify or Vercel, you need to ensure that you have a recent version of Go installed in their environment too.

I deploy this website using Netlify, and so I know how to do that there — Set the GO_VERSION environment variable to a recent version like 1.18 in the Environment variables section in Netlify Build & deploy settings.

In a nutshell #

  1. First convert your Hugo site to a Hugo module.
  2. Then replace the theme in your site config with a module import.

Enjoy! 🍾

References #

  1. It is recommended to git commit the go.sum along with your site’s go.mod. From the Go Modules documention: Ensure your go.sum file is committed along with your go.mod file. See FAQ below for more details and rationale. ↩︎

  2. Trust me.. once you get a hang of the Hugo Module system, your site will have more than one! ↩︎