The Two Ways to Extend Hugo Sites
When you want to add themes or plugins to your Hugo site, you have two main options: git submodules or Hugo modules. Of course, you could just download and copy files manually, but we’re trying to be rational here.
Hugo modules are the newer approach, officially recommended by Hugo developers, ChatGPT, and Perplexity. However, if you’re comfortable with Git, submodules work perfectly fine and that’s what I use.
Why I chose git submodules
Transparency and customization
With git submodules, you can directly view and modify theme files. Want to tweak a template or understand how something works? Just navigate to the theme directory and explore. It also makes life easier for Copilot/Cursor since it can access the actual files without any extra steps.
With Hugo modules, you need an extra step: run hugo mod vendor
first to populate the _vendor
directory, then explore the files there. Don’t forget to clean it up afterward when updating modules.
Dependabot integration
Dependabot is fantastic: it tracks dependencies and creates automatic update pull requests with release notes and changelogs. Git submodules are fully supported by Dependabot.
Here’s my Dependabot configuration for automatic updates:
# .github/dependabot.yml
version: 2
updates:
# Update submodules automatically (e.g. themes)
- package-ecosystem: gitsubmodule
directory: /
schedule:
interval: weekly
Warning
Unfortunately, Dependabot doesn’t support Hugo modules yet. The open issue from 2023 remains stale because Dependabot uses standard Go commands for modules (go get
and go mod tidy
) instead of Hugo-specific ones (hugo mod get
and hugo mod tidy
), which delete your go.mod
and go.sum
files. Of course, you can create a custom action, run commands manually and use Create Pull Request GitHub action, or simply switch to an alternative solution like Renovate, but again, this requires extra effort.
Info
If you want to update submodules manually, I use: git submodule update --remote --merge
. This command comes from the second Stack Overflow answer and is better than the first accepted answer because it works regardless of whether the remote branch is called main
or master
.
Adding a theme as submodule
If I managed to convince you, here’s what you need to do:
# Add theme as submodule
git submodule add https://github.com/author/theme-name.git themes/theme-name
# Initialize and update
git submodule update --init --recursive
Don’t forget to add the theme in your config file (config.toml
, config.yaml
, or config.json
). For TOML: theme = "theme-name"
or theme = ["addon-name", "theme-name"]
if you already have multiple themes/addons.