Thoughts on Hugo

This blog is generated using Hugo. A documentation site I’m rebuilding is also made with Hugo. These two projects have given me a chance to get to know the tool, to appreciate it at times, and to curse it otherwise.

Some of my complaints are inherent to static site generators, others are more specific to Hugo.

Your Directory Tree Is Configuration Code

In its simplest form, a static site generator takes a directory tree full of markdown files, and cranks out an identically structured directory tree full of HTML files.

It’s expected that the shape of your directories will affect how the generator works.

Hugo has accumulated such a vast array of capabilities that the simple model described above has multiplied to the point where it’s no longer easy to know what effect a file has, or why some file does not have the effect you think it should.

Have a look at the template lookup order “help page”. Hugo accomplishes a lot here, with its multi-language abilities, and its taxonomies, etc… But you can see from the number of examples and possible lookup places that the capabilities are paid for in complexity.

I don’t think the filesystem is the right tool to describe the complex relations between posts and languages and templates and output formats. It’s too easy to get lost. Or Or

It took me a little while to understand that and are not the same thing. One is used to showcase a list of posts, the other one is the post itself within a page bundle. Or something like that. I used the wrong one for a while and got no errors, but my table-of-contents didn’t seem to work. I spent a lot of time sorting that out.

I ran into a number of subtle behavior gotchas like that with the tool. For instance there are different “kinds” of pages and different “types” of pages, and it affects whether a page shows up in a collection of pages among other things. (Don’t ask me to explain, I can’t.) The point is there are lots of concepts, and these concepts don’t all work intuitively, and the difference between the tool behaving one way or the other can boil down to a single underscore in a file name.

I ran into another issue where I wanted to render markdown in content within a shortcode. Here again one little character makes a big difference. This {{< shortcode >}} is not the same as {{% shortcode %}}. This behavior has changed over time, causing confusion, and guess what? Though I read the docs, the behavior on my site is opposite what the docs indicate.

Of course it’s all my fault. Everything is documented. The thing is the documentation runs longer than your typical “learn a programming language” volume. I haven’t actually counted the words but it seems like there is a lot more than I should have to go through to render a blog or some docs site. The section on “Content Management” has 24 pages, each bringing in new concepts and new flags to tweak in your configuration.

You might say “it’s powerful, it’s up to you to learn it”. I won’t argue it’s not powerful, but something this powerful could be more sane to use if it relied on something other than the presence of an underscore to mean something about a file. Is the file tree truly the best abstraction for the user to accomplish their goals?

All Text No Tools

I understand the draw of using text files in a file tree: they can be worked on from the user’s favorite text editor, and it can all be checked into version control. Fine.

The problem is the tooling for text editors is weak. If something is this complex and powerful, and intended to be seen as “code” my expectations grow accordingly: where is the live error reporting? Where is the “debugger”? Autocomplete?

For instance, you can create a link to a page within your site using a “relref". The cool thing is that the site will fail to build if you put a typo in the link. Guaranteed link correctness! I like. But the way it works is you type your stuff in your text editor, at some point hit save, then and only then your Hugo build will throw an error.

Does this remind you of anything? It takes me back to engineering school in the nineties where I was learning Fortran 77 (and the new hotness Fortran 90!) Write code. Save. Run compiler. Oops error. Find error file and line. Think some. Aha! Fix. Save. Run compiler. And on and on…

I don’t know about you but I don’t work like this anymore. Whether I write Go or Typescript, I get to see my mistakes as I type them, and I get suggestions for what is actually correct. The creators of those languages provide tools to help me because they feel my pain. I’m writing cryptic text but I’m getting a lot of help. When I do things in Hugo I get almost no help.

If a template doesn’t work as you expect and you want to step through it as if it were normal code, too bad. A helpful docs page recommends you put “printf” statements in your template. The nineties called, they want their debugger back.

Why would I not get an autocomplete when I create an internal link using relref? Shouldn’t I get a red squiggly underline if my relref has a typo? How about autocomplete when using a shortcode? (I tried installing this extension to my VSCode but it doesn’t seem to be doing much apart from causing an autocomplete popup for every single English word I type.)

I’d like to be able to click on any shortcode, or select any file, and have a tool tell me where it’s sourcing the templates that will be used to render it, and where the output will go.

But I don’t have any of that, so when something doesn’t work quite work like I expect I end up just playing a lengthy and frustrating guessing game.


I started off really wanting to like Hugo. I got into it after I realized I was going to have to put my web content authoring tool on the backburner.

I figured if I can’t build something great, then I should pick the best of what exists and learn to live with the things I disliked.

It’s been over a year now, and I just can’t find love for Hugo. I use it, it’s effective when it’s all set up correctly. But does it feel like a wonderful powerful tool? A bicycle for my content-generating mind? Hardly.

There is a great talk by Alan Kaye dubbed “Is it complex? or did we make it complicated?” that applies here.

Static site generators have stepped over and beyond the bounds of what made them great: they were simple tools for simple problems. By making them do so much more they became complicated, and less effective.

PS: I’m sorry for not including proper code snippets. Turns out if I wrap Hugo short codes in a code block, Hugo tries to interpret them as actual shortcodes. If I escape the characters with \ it renders the slashes, and if I don’t it crashes with “Null pointer dereference error”. Yay.

This was day 15 of the #100DaysToOffload challenge.

Olivier Forget

Los Angeles, USA
RSS Email Mastodon

Aerospace Engineer turned sofware developer and bootstrappin' entrepreneur.