# How to add a theme using modules (for beginners)

**URL:** <https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665>\
**Category:** tips & tricks\
**Created:** [September 8, 2019, 4:35pm UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665 "2019-09-08T16:35:37Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![chreliot](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/chreliot/32/488_2.png) [@chreliot](https://discourse.gohugo.io/u/chreliot)\
**Post date:** [September 8, 2019, 4:35pm UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/1 "2019-09-08T16:35:37Z")

</div>

It took me longer than I expected to figure out how to add a theme to a site the new way: using modules. It is very easy — much easier than the two other methods I’d used to add themes — once you know what you need to do. Here’s how it worked, in three short steps.

First, at the command line, go to the top level of your project. Initialize your site as a hugo module. To do that, type `hugo mod init` and then the url where the site will be deployed (without a trailing slash at the end). For example:

```auto
hugo mod init yourname.github.io/sitename

```

for GitHub Pages user `yourname` deploying `sitename`.

Second, add the theme as a module in your config file. Here is how it looks to load the hugo-xmin theme in a config file which uses the default toml format:

```auto
[module]

  [[module.imports]]
    path = "github.com/yihui/hugo-xmin"
    disable=false

```

The `[module]` indicates that this is a section of the config file for modules, and then the `path` is just the url fetched from GitHub for the theme I wanted to add. A second theme could even be added below, in the same format, especially if one of them is marked `disable=true`. That even allows quick switching between themes!

Third, tell hugo to use this theme. That looks like adding the following to your config.toml file, where `hugo-xmin` is the name of the theme:

```auto
theme = ["hugo-xmin"]

```

Note that this command will also look at a series of theme items or other code, prioritizing the ones on the left, so the following would load the hugo-xmin theme, adding to it (and overriding it) with anything in the `my-shortcodes` module:

```auto
theme = ["my-shortcodes", "hugo-xmin"]

```

To use that module of course we would have had to load it, with something like

```auto
  [[module.imports]]
    path = "github.com/yourname/my-shortcodes"
    disable=false

```

And you now have a theme loaded with your extras.

(Corrections and improvements from more advanced users welcome!)

---

<div class="post-metadata">

**Author:** ![bep](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/bep/32/3332_2.png) [@bep](https://discourse.gohugo.io/u/bep)\
**Post date:** [September 8, 2019, 7:34pm UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/2 "2019-09-08T19:34:26Z")

</div>

> [@chreliot](#):
>
> [[module.imports]] path = “[github.com/yourname/my-shortcodes](http://github.com/yourname/my-shortcodes)”

Great. One little correction:

This:

```auto
[module]
  [[module.imports]]
    path = "github.com/yihui/hugo-xmin"
  [[module.imports]]
    path = "github.com/yourname/my-shortcodes"

```

Is the same as:

```auto
theme = ["github.com/yihui/hugo-xmin", "github.com/yourname/my-shortcodes"]

```

You don’t need both.

---

<div class="post-metadata">

**Author:** ![divinerites](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/divinerites/32/12625_2.png) [@divinerites](https://discourse.gohugo.io/u/divinerites)\
**Post date:** [August 8, 2020, 8:56am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/3 "2020-08-08T08:56:49Z")

</div>

Thanks all for those informations. Since [this post](https://discourse.gohugo.io/t/hugo-modules-for-dummies/20758/8) is now closed I hijack this thread to give some more hints.

After **not succeeding to use modules** even after reading those great post and the doc, even if I’m pretty comfortable with Hugo, I finally got some aha! moment when I realised that you need to understand somethings the Golang users know for a long time, but hidden for us poor mortals only using Hugo.

Do not hesitate to correct me if something is wrong or not really accurate. Here is the 2 simple things:

## The path name module.

- If you want to create/develop a module, you create your git folder `module1-hugo` as usual.
- But the name module you give **cannot** be a local name (aka `module1-hugo`).
- It has to be with a **domain name as prefix** (aka `github.com/divinerites/module1-hugo`)
- So now you can initiate the Hugo module with the command : `hugo mod init github.com/divinerites/module1-hugo`, and reference it later in your `path` directive.

## The version numbers

- Unless you’ll give a (semantic) **tag version number** (aka `v1.0.3`) to your git commit, trying to use modules will fail with diverses error messages.

If you follow those 2 basic (for Go & Go modules users) recommandations, then using Hugo Modules is easy and so powerful (thanks Bep for this fantastic implementation).

May be just 2 other things, already in those great tutorials, but better say that again here:

- A useful basic commands to **update only one module** from your internet repository : `hugo mod get -u github.com/divinerites/module1-hugo`
- When you want to update/develop locally the beauty of modules is that you just add a `replace` directive for the module in your project `go.mod`, and bim bam boum, the local module folder is in use, with a fresh Hugo reload in millisecond. No need to do the merge/push/tag/update dance. **Brilliant**.

`replace github.com/divinerites/module1-hugo => /Users/mycomputername/Documents/Git/module1-hugo`

---

<div class="post-metadata">

**Author:** ![bep](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/bep/32/3332_2.png) [@bep](https://discourse.gohugo.io/u/bep)\
**Post date:** [August 8, 2020, 10:17am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/4 "2020-08-08T10:17:48Z")

</div>

> [@divinerites](#):
>
> Unless you’ll give a (semantic) **tag version number** (aka `v1.0.3` ) to your git commit, trying to use modules will fail with diverses error messages.

Your description is spot-on and very good. I just want to add this:

- It’s perfectly fine to not use tags at all, and I find that it doing `hugo mod get -u` will do what you expect in that situation (get the latest commit).
- You can append the version number or Git sha ref when doing “getting”, e.g. `github.com/yourname/my-shortcodes@v1.0.0`. You can also edit the `go.mod` file and then running Hugo.
- You can also have versioned mono-repos, see [Tags · bep/hugo-jslibs · GitHub](https://github.com/bep/hugo-jslibs/tags)

---

<div class="post-metadata">

**Author:** ![divinerites](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/divinerites/32/12625_2.png) [@divinerites](https://discourse.gohugo.io/u/divinerites)\
**Post date:** [August 8, 2020, 10:19am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/5 "2020-08-08T10:19:36Z")

</div>

Super cool. Thanks.

---

<div class="post-metadata">

**Author:** ![bep](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/bep/32/3332_2.png) [@bep](https://discourse.gohugo.io/u/bep)\
**Post date:** [August 8, 2020, 10:23am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/6 "2020-08-08T10:23:35Z")

</div>

> [@bep](#):
>
> It’s perfectly fine to not use tags at all

But you will then lose out on the version selection in use:

> **[Modules Part 03: Minimal Version Selection](https://www.ardanlabs.com/blog/2019/12/modules-03-minimal-version-selection.html)**
>
> Ardan Labs is trusted by small startups and Fortune 500 companies to train their engineers and develop business software solutions and applications.

---

<div class="post-metadata">

**Author:** ![somratpro](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/somratpro/32/12420_2.png) [@somratpro](https://discourse.gohugo.io/u/somratpro)\
**Post date:** [November 9, 2020, 4:19am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/7 "2020-11-09T04:19:06Z")

</div>

And how can I add the exampleSite?

---

<div class="post-metadata">

**Author:** ![davidsneighbour](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/davidsneighbour/32/24507_2.png) [@davidsneighbour](https://discourse.gohugo.io/u/davidsneighbour)\
**Post date:** [November 9, 2020, 10:45am UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/8 "2020-11-09T10:45:56Z")

</div>

I would copy the contents of that folder to my own content folder. It’s a sample site, so I will probably change it and adding it as mount makes no sense then.

---

<div class="post-metadata">

**Author:** ![aurelienpierre](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/aurelienpierre/32/18358_2.png) [@aurelienpierre](https://discourse.gohugo.io/u/aurelienpierre)\
**Post date:** [December 10, 2022, 12:36pm UTC](https://discourse.gohugo.io/t/how-to-add-a-theme-using-modules-for-beginners/20665/9 "2022-12-10T12:36:32Z")

</div>

There is something I just found out after developing a website and theme with Hugo for a week.

I have no background in Golang, but coming from Git, I thought the Hugo module init was similar to the the git submodule init. It’s not.

Let’s say you have 2 repositories : the imported and the importer.

In Git, your run

```bash
$ git submodule add https://github.com/USER/imported
$ git submodule init

```

**from within the importer repo**.

In Hugo, you run `hugo mod init https://github.com/USER/imported` **from within the imported repo**. This creates a sort of header to the **imported** repo that makes it self-aware of its own URL and importable later. Then, in your **importer repo** , you link the imported repo with the config params:

```bash
[module]
  [[module.imports]]
    path = "github.com/USER/imported"
    disable = false

```

The Hugo doc and even this post talk about “initializing a project” without mentionning which one (imported or importer) it is. The Hugo logic implies you have control over the imported repo to initialize as a module, while the Git logic implies nothing but doesn’t mount as subfolders as nicely.
