Are Hugo modules the suggested way to provide and receive themes

Thank you guys very much for Hugo 0.56.0! It seems really very cool and powerful.

A few questions concerning the new Hugo modules. I hope it is not too general:

Would you developers suggest to generally use Hugo modules to implement themes (instead of using git submodules)?

How would simple ‘workflows’ look like to provide or get e.g. a theme, a shortcode or a set of shortcodes?

I use a set of own shortcodes for all front end projects and handling them always feels a bit cumbersome. Managing them with modules and being able to use selected ones only would be great.

Thanks again.


You have good questions, and I think it helps to remind ourselves that we’re not a big team doing this, so there are still work to do on the documentation and “processes”. For starters, I will one of these days rewrite the Theme Site build script to use modules.

As to “getting a theme” etc. it’s in the documentation. In short, if you have initialized your main project as a Hugo Module, you can just import projects on GitHub/GitLab etc. by their path in config.toml and it will all happen automagically. In this demo video what I do is just toggle the “active” flag on the imports:


A related tip: If you build themes that imports other shortcode components etc. you can run hugo mod vendor and it will write every module dependency to disk – and people who use your theme can use it as it was all “locally”, no need for them to have Go/Git installed etc.

1 Like

Thanks a lot, @bep. Appreciate it very much.

I will deeply dig into it and give feedback.

Jepp, I know! Take your time. I would be happy to help; but I’m just a front end guy.

Hey, quick question/use case:

Say I have 2 locally developed sites, they share a locally-developed theme (github is not involved in any way). Can I use [module.imports] in this case? (I’m not seeming to be able to do it… also tried with a symlink (aka alias on mac))

In your project, your mounts can be symlinks, but the import path must either be

  1. A path below /themes
  2. A module name

I think you can use both of the above locally, but I suspect you need to do some trickery with 2, probably involving adding a replace directive to go.mod.

hmmm, i’ve got something to work (not sure if I fully understand it, through):

Here is the situation:

// Directory with several local sites 

├── hugo-site/
│   ├── content/
│   ├── config.toml
│   └── go.mod
└── hugo-theme/
    ├── layouts/
    └── config.toml

go.mod is "empty (is this correct?)

module .

go 1.12

Now, there seems to be some interesting behavior depending when theme is set in the sites’s config.toml relative to when modules are imported.

# sites/hugo-site/config.toml

baseURL = ""
languageCode = "en-us"
title = "My New Hugo Site"
disableKinds = [
# theme = "Hugo Theme" > server fails if theme set here

  min = "0.56.0"
  path="../../hugo-mod-theme" # I'm not sure why i need to go up 2 directories here...

theme = "Hugo Mod Theme" # works when theme set here

is this expected behavior?

Yes, yes.

That is relative to the themesDir setting. You may get a simpler setup if you set themesDir=.. or something.

I also noticed that the ERROR message has changed instead of theme not found... it now reads module not found... so I suppose that as of 0.56 themes are considered modules even in terminology.

My setup is similar now:

    min: 0.56.0
    - path: ../../../hugo-themes/default-hugo-theme

go.mod may be missing(?), may be empty (see above) or may contain:

module hugo-themes/default-hugo-theme

go 1.12

All three cases seem to work locally.