12 Helpful and Time-Saving Tips for Hugo Beginners

by Radu

I recently switched my WordPress blog to Hugo. While working on it, I decided to note down things that I thought most of you will face.

Things like how to remove automatic IDs from your headings, how to enable raw HTML in your markdown files, and so on. Just common stuff that I believed most of you will want to implement or understand without losing a lot of time doing research.

I’ll keep updating this list with time. You can also send me your tips.

Here goes.

12 Tips for Hugo Beginners

There are a ton of tips for Hugo, but I’ll only focus on those that cover common situations.

1. Get the extended version if you use Sass or WebP

Hugo comes in two flavors:

  1. Standard, which is not the official naming. I just call it that.
  2. Extended.

If you want to let Hugo compile Sass/SCSS, then you need to install the extended version.

The same goes for the WebP image format. If you want Hugo to process your .webp images, you’ll need the extended version. By processing, I mean changing them in any way, such as resizing.

If you just want to simply add WebP images to your content, you don’t need the extended version.

2. Removing IDs from your headings

By default, the Goldmark markdown library used by Hugo adds your heading as an id.

For example, the above heading would appear like this in my code:

<h3 id="remove-ids-from-your-headings">Remove IDs from your headings</h3>

If you don’t use a table of contents, then you probably want to disable this feature by adding this to your config.toml file:

  autoHeadingID = false

3. Allowing raw HTML in your markdown

By default, the Goldmark markdown library used by Hugo won’t allow raw HTML in the .md files.

And with the use of shortcodes and render hooks, you normally wouldn’t need to enable this feature. But there are cases when you might need to add some raw HTML.

For example, I tend to add gifs sometimes. And it’s quicker for me to just copy and paste the code from Giphy than calling my shortcode.

So, if you think you need to add raw HTML to your markdown files, add this to your config.toml file:

  unsafe = true

4. Changing the title will change the URL

Figuring this out kept me busy for an hour because I couldn’t realize what was going on.

When you create a page, Hugo adds the folder’s name as the title in the Front Matter. Then, it uses that title as the URL of the page.

I created my About and Contact pages and added them to the menu, in the config file, where I also specified their URLs.

Now, after some time, I changed their titles from About and Contact to something else and didn’t think much of it.

But, after a bit, when I clicked on them in my navigation menu, they returned 404 Page Not Found.

It took me an hour to realize that I changed the title in the Front Matter; therefore the URL was changed accordingly.

So, keep in mind that the URLs change with the titles.

If you want to set a fixed URL that doesn’t change with the title, you need to add a url parameter in the Front Matter, like this:

url: "/stay-like-this/"

This is for Front Matter written in Yaml, which is the default.

5. Add hyphens inside the curly brackets to prevent white space

When you write template code, and you want to add proper spacing to it to look clean and improve readability, you can end up having white spaces inside your HTML tags.

Here’s what I’m talking about. Let’s take this code for example:

<body class="{{ if .IsHome -}} home {{ end -}}">

This code adds a home class to the <body> tag if the page is the homepage.

You can notice those two hyphens in the closing curly brackets. Without them, the HTML tag will look like this on the front-end:

<body class=" home ">


There will be white spaces on the sides of the class. Those hyphens eliminate that white space.

Some people always add hyphens in the opening and closing curly brackets, which is practical. You can do that too.

6. Hugo will use code that’s commented out

Commenting out template code using HTML comments won’t prevent Hugo from picking it up.

That kept me busy for a bit, too, when I first commented out a piece of code. Hugo kept showing me an error for it.

7. Hugo won’t remove generated files before building

This also kept me busy.

When I first built the blog, Hugo generated a bunch of RSS .xml files. Since I don’t want that, I went to the config.toml file to add disableKinds = ["RSS"].

Then, I rebuilt it, but the files were still there. I tried this, tried that, built again… nothing. Until I finally found out that Hugo won’t remove files that were previously generated.

Running hugo does not remove generated files before building. This means that you should delete your public/ directory (or the publish directory you specified via flag or configuration file) before running the hugo command. If you do not remove these files, you run the risk of the wrong files (e.g., drafts or future posts) being left in the generated site.

So, I had to remove everything from the public folder, then build again.

8. Hugo won’t automatically load your 404 page template

When you create a layout for a page, hugo server picks it up and displays it. Unfortunately, Hugo won’t do this automatically for the 404 page. You’ll have to add /404.html as the URL to view it.

hugo server will not automatically load your custom 404.html file, but you can test the appearance of your custom “not found” page by navigating your browser to /404.html.

9. Featured image(s) for Open Graph and Twitter Cards when using Page Bundles

For Open Graph and Twitter Cards, Hugo will take the image(s) specified as images: ["example.jpg"] in the Front Matter.

If you’re using Page Bundles, there’s going to be a problem, in my opinion.

Let’s say that you have a Posts section for your articles. You’ll need to specify the whole path of the images, like this:

images: ["/your-post/path-to-image.jpg"]

Or, if you keep the /posts/ slug in front of your posts’ URL, you might need to add that, too, like:

images: ["/posts/your-post/path-to-image.jpg"]

This is kind of annoying, especially if you need to add multiple images. Moreover, if you change the post’s URL or section, the image path needs to be changed as well.

Sure, you probably can create a function in the Archetype, but I prefer the alternative offered by Hugo.

If page bundles are used and the images array is empty or undefined, images with filenames matching *feature*, *cover*, *thumbnail* are used for image metadata.

So, what I’m doing is to remove the images parameter, and simply add an image that contains “feature” in the filename. Hugo picks that up automatically to add it to the metadata for Open Graph and Twitter Cards.

And, in case I’ll need a featured image to insert somewhere, I created a parameter called featured_image, to which I add the featured image created for the metadata. So, I use it like this:

featured_image: "feature-my-image.png"

Note that I don’t need to add the whole path, just the filename.

Now, if I ever want to use it somewhere in my content, I can do it like this:

{{ with .Resources.Get .Params.featured_image }}
    <img src="{{ .RelPermalink }}"/>

I tested it, and it seems to work fine.

To summarize – Hugo adds the image automatically in the metadata based on the filename match, and I also declare it in the Front Matter so I can use it in my content if I want to.

10. Try adding short filenames when using Hugo processing

I’m using Hugo to resize my images to serve them in a responsive way via HTML, using srcset.

But Hugo adds big filenames to the resized images because it:

  • Encodes the name;
  • Adds content hash;
  • Adds resizing instructions.

So, an image’s filename will look like this:


Now, some people have said that this can trigger the long filename error in Windows.

My advice is to try to add short names for your image files, so you don’t make the anaconda bigger than it needs to be.

I believe it does this to other files, too. For example, CSS files.

If you check some sites created with Hugo, including Hugo’s official website, you’ll see CSS files like this:


11. Figure element will get wrapped in paragraph tags when used in image render hooks

I wanted to use an image render hook to resize images, but I wanted to wrap them in <figure> because I sometimes use captions. I saw quite a few people trying to accomplish the same thing.

The thing is that Hugo wraps <figure> in <p> tags, which is invalid HTML because <figure> is a block. And the browsers automatically turn them into two empty <p></p> tags, placed above and under the figure tag.

Image from Github

I thought it was preposterous, so I tried to fight it because I wanted it to work my way.

This is until I found this Github comment, which is from someone who works on the Hugo project, I think.

I only showed a part of it.

What is said there made sense to me because:

1. The markdown wraps in <p> tags everything that’s considered an inline HTML element, including <img>.

Yes, <img> in <p> tags is valid HTML. It looks weird to me, too, because I never used it like that.

2. <figure> is a block, but the render image hook expects you to add an <img> tag there, which is an inline element. Therefore, it automatically adds <p> tags, regardless of what you put there. You can add a <div>, and it will wrap it in <p> tags.

So, I stopped fighting the system.

I went ahead and created a shortcode with a <figure> tag because Hugo can process images there as well. Also, shortcodes are not wrapped in <p> tags. Then, I created a render image hook with <img>.

When I want to add a caption, I use the shortcode; otherwise, I use the render hook.

12. Hugo can minify HTML on build

Obviously, the output HTML will be a mess. One way to hide that mess – and also improve the performance score a bit – is to minify the HTML.

Hugo allows you to do this when building the site, by using the command:

hugo --minify

That’s a Wrap

There you go. These are the tips that I hope will save you time and headaches. I sure wish I would’ve known them before. They’d have saved me at least a day.

If some info is outdated or incorrect, or you have anything to add, say or ask, please contact me via Twitter or email.

About Radu

I've been working online, from home, for over 9 years. I learned a lot of different stuff related to websites. My main expertise is WordPress, but for some time, I started focusing more on web development.