How do I do theme development with an example site in the repo?

It looks like all the themes include an exampleSite at the root of the project. It’s not clear to me if people are using the exampleSite for development or only a demo. I tried using it for development by symlinking the project root in the themes folder of the exampleSite but hugo didn’t like my use of symlinks. I don’t remember what errors I got but it wasn’t working. How are other people going about theme development using an exampleSite?


Create a copy and modify.

Create a copy of what? Create a copy of a theme or an example site? I understand how to have an example site but right now I have the example site in a different repo and then check the theme out in the the exampleSite/themes/ directory. I’d like to have a clean way for the example site to live in the same project as the theme without having to checkout the project twice for development: once for the example project and another time in the themes directory of the example site for the theme. To illustrate what I’m imagining, one solution would be being able to give hugo a path instead of a name for the theme, i.e., hugo server -t ../.

My directory structure looks like this.


The example site. The exampleSite’s main purpose is the demo site. A site should live outside of the theme, so create a copy and put it somewhere else. Then modify that.

TLDR: If your setup isn’t very complicated you can mostly stay with the classic folder structure without using exampleSite. If your site/theme grows in complexity feel free to read on.

As @bep already mentioned: the exampleSite folder is mostly used to the demos at our theme site if you have a added some advanced logic. A lot of my themes required a custom setup that goes beyond a standard config file. For example, I added custom content to show certain features in blog posts or I’ve made use of the data folder. These files are usually not part of a theme since this file reside in the root directory of a Hugo site.

Maybe it helps if you take a look at the setup of one of my themes to get a practical example. Another great side-effect is that I can directly ship my theme with all files that are required for the custom structure that I mentioned above.

Within the README I provide some instructions for the users of how to copy the right files from the exampleSite folder to the right destination, e.g. that all files under exampleSite/data/ remain to the data/ folder in the root directory.

I hope I could clarify some things.

@digitalcraftsman, thanks for creating the agency theme. It’s probably what I would use as a starting part for any single page site I want. Apparently I’m failing to communicate my problem. Your readme has a description of how to use the theme. What I need is a description of how to do theme development. For instance, I would like to have the exampleSite in the theme project. I would like to do hugo server -w from the root of the exampleSite directory and have it use the theme I’m building at the root of my project. Maybe this is impossible but I’m just wondering how people go about developing themes. Right now I just have my example site as a separate project and checkout the theme project in the themes directory but this seems less than ideal. Do you use the example site for theme development or do you just throw that in there when you’re done?

@AldenJole The following wouldn’t work:

cd exampleSite
> themes/THEMENAME/exampleSite/
hugo server -w

This only works on the demo site because a shell script generates the site. It detects standard folders like data and content and or a custom config file within exampleSite.

All the custom files and folders copied into a temporary folder that represents a complete Hugo site that you would generate with hugo new site SITENAME. Now Hugo finds everything in the root folder is now able to render the demo site without any issues.

But how does the exampleSite know to use the THEMENAME theme?

The shell script that generates the demo sites knows two possible ways to create the demo pages for your theme:

  • If your theme does not contain an exampleSite folder it generates yours like you would run the following commands in the terminal:
hugo new site .
mkdir themes
cd themes
git clone
cd ..
hugo server --watch --theme=THEMENAME 

It’s like using the default config file generated by Hugo (with hugo new site .) where you just specify which theme should be used.

  • The second option is to provide an exampleSite folder. The bash scrip will detect exampleSite and copies everything into the root directory of the Hugo site. Now your custom config file, your own content files etc. will be used instead.

But I think @bep could clarify the details if needed since the created the bash script.

However, after taking a look at your Github profile I guess you’re currently working on the CFA Brigade Theme. No it depends on the customization of the config file if you need exampleSite. For example, this is the case if you added new variables under params in the config file.

Within the layout you’re using custom variables from params. Without an example config file in exampleSite Hugo and the bash script wouldn’t which values to insert. Hugo would treat your theme as under the first bullet point by using the default configuration.

My understanding is that what I want to do is not currently possible. If I could specify the theme by path, then I could do something like

git clone
cd theme
hugo server --watch --themePath . --source exampleSite

This would allow hugo server to --watch both the theme and the example site. As it is currently I do

git clone
cd site
mkdir themes
cd themes
git clone
cd ..
cd ..
hugo server --watch

This works okay for development but it doesn’t keep the theme and the exampleSite in the same repo which is less than ideal. I think hugo is also watching the theme/.git which could eventually cause problems. If I ever wanted the theme to show up on the themes page, I would have to copy the example site repo into the theme repo which would cause the example sites to get out of sync.

A few moments ago I discovering your main Hugo site. And with exampleSite do you mean this repo? Because this could explain some confusion.

The theme itself is in it’s own self-contained repository. This would allow you to distribute it easily. I someone wants to setup a new website with your theme, you can treat the site and the theme as two independent peaces of code.

For the setup you instruct the user to create a new Hugo site and to download the theme into the themes folder.

hugo new site .
mkdir themes
cd themes
git clone
cd ..
hugo server -w -t=themename

Since your theme depends on a customized config file you need to distribute a version with default values with the theme. Before running hugo server -w -t=themename this config file needs to be copied into the root directory.

You could apply the same steps to your main Hugo site. Just create a themes folder, clone the theme into this folder and your site should run as wished. Your website and theme remain independent.

Now we can demistify exampleSite. With exampleSite I don’t refer to your main Hugo site. You can name it however you want. It does not affect the use of Hugo at all.

With exampleSite I mean a folder, not a repository, that is placed inside a theme. Let’s take a look at the Cactus theme. I’ve created an exampleSite folder within this theme.

You could create and exampleSite folder in your theme and place there the needed config file for the theme. It doesn’t need to be the config file of your main Hugo site. Just a config file with default values is required. Now you’ve a place where the users can find the config file if they want to setup their own website with your theme.

If I ever wanted the theme to show up on the themes page, I would have to copy the example site repo into the theme repo which would cause the example sites to get out of sync.

You don’t have to put your main Hugo site into theme/THEMENAME/exampleSite. They both stay independent.

Maybe you want to share the theme with others and present it under the theme site. In order to generate a demo we would need to have a config file for your theme. Like new users how setup a website with your theme, the config file needs to be copied into the root directory.

Hugo is now able to generate your a demo. exampleSite is just used to ship your theme will all things that are necessary to run your theme.

We don’t need your main Hugo site in order to create a demo. We need just the theme and all the required files (like the config file).

Okay, I’m having a similar issue.

What I do, is have the theme I am working on in its own GH repo. I then use the ExampleSite directory in that repo as the site that I “build” to test my theme. If we assume I created a theme called castanet then inside the examplesite directory I make a themes directory and inside there create a symlink of castanet -> ../../castanet

(Oh, and inside examplesite I create a .gitignore that ignores the themes directory)

This works quite well - I can run hugo server inside the examplesite directory. But “watch” doesn’t work - what do the rest of you do for testing your theme while developing it?

This works exelent with hugo server for me:

But only after this fix:

(which isn’t in a Hugo release, must build the source, go get etc.)

1 Like

Defining themesDir = "../.." in the config file makes the exampleSite folder working out of the box as complete Hugo website. But if users wan’t to use the config file for their actual project they would have to remove the themeDir variable. Otherwise, Hugo would look at the wrong place for a theme.

Is this a tradeoff?

Let it put it this way: The theme I linked to would not have existed without that trafeoff. So def worth it. There are other current workarounds, too, like:

env HUGO_THEMESDIR="../.." hugo server 

Should also work.

But if I cannot clone a random theme and cd into the exampelSite and just build it … then I would look at it as a buggy theme.

That said, there are improvements to be had in the whole “theme resolving” area. Happy if someone could fix it.

This worked like a charm. Thanks!