(The (future) ultimate guide on) How URLs work (in HTML, not Hugo)

(Work in Progress. Bear with me.)

I often read in this forum questions like the following ones:

  • My site does not load styles when deployed.
  • I cant display image X on page Y.
  • It works locally, but when deployed, it does not work.

(I used my own words, you probably use different ones)

The issues can in most of the cases, dare I say 99% of cases be tracked down to one single problem: How do links work.

The problem is not HUGO; it’s how HTML works.

Please try to understand how URLs work before complaining about things you don’t understand. Every time those URLs worked as expected by coding standards. Just not as expected by you, the “not-knowing” “newbie”.

Here is a short introduction to URLs (links, permalinks, whatever you want to call them).

Let’s say we have the following structure on our site (simplified for convenient’s sake):

Hugo folders:

  • /content/
  • /content/an-article/
  • /content/
  • /content/posts/2019/
  • /content/posts/2018/

Folders on the resulting website (run hugo and check out /public) in the same order:

  • index.html
  • an-article/index.html
  • blafasel.html
  • posts/2019/a-post.html
  • posts/2018/a-post.html

Now, let’s talk links, shall we?

In posts/2018/a-post.html there is a link blafasel.html. Where is this link going?

Wrong: blafasel.html
Right: posts/2018/blafasel.html


Good Questions. Try to follow me here:

Two terms: relative links and absolute links

What is “relative”?
Relative links point to files relative to the current one. They start without a dash (/) in the beginning and search for the file from the current position. If you are in posts/2019/a-post.html a link to blafasel.html will always search for posts/2019/blafasel.html. If you want to search for the existing file from above, the one in the root directory, you need to use “directory change indicators” to “travel” up two levels like ../../blafasel.html. That will work. But it’s not the proper way to do this. Geeks, as well as Nerds, will sneer on you. Read on, fellow mate.

What is “absolute”?
Absolute links are interpreted from “server root”. In Hugo, the server root is the public folder. Absolute links start with / - always and every time. This means, that /index.html (or / itself) ALWAYS points to the homepage, the index.html file inside of the public directory. Always. Every time. If in posts/2019/a-post.html you link to / people will end up on the home page. If you link /blafasel.html from there - people will end up at blafasel.html (the one from my list above).

Let’s be complicated. You want to link from posts/2019/a-post.html to posts/2018/a-post.html. How do you do that? There are two ways:

Relative: ../2018/a-post.html
Absolute: /posts/2018/a-post.html

Now. Ask me what link-type to use, what link type do “we” prefer? :slight_smile:

Ask me!

If you know the absolute path, then ALWAYS use the absolute link. Sure, links might change, but in these days we have tools like Atom, Sublime Text, WebStorm, whatever, and those tools can search and replace. An absolute path is “dummy safe”. Relative paths need more brain matter to point to the right position.

Apart from this, you know that the image in /static/images/logo.png will always be (absolutely, get it, hehe) available at /images/logo.png. NOT images/logo.png.

Base Path / Domain names

Yeah. I am not a fan of these. If you have a website and you want to link to your stylesheet, why then link to https://yourdomain/path/to/your/stylesheet.css if /path/to/your/stylesheet.css would do the same job? Think about moving your site from domain to domain. The first path needs to be fixed to the new domain, the second path will always be right. Apart from the minimal, non-countable amount of bytes you save from not having your domainname in the HTML in each and every link.

Final Remarks

I will extend this post with “real world examples” over time so we can just link to it when someone posts a question like “My stylesheet does not work when I deploy my website”. Stylesheets should either be done via PIPE (you won’t use paths then) or be linked absolutely. Everything else is smelly codingstyle. Google it. You don’t want to have smelly code. Smelly code is done by outsiders. The loosers club. Peep peep Ritchy. If you get my drift.


Hi @pkollitsch, thanks for the write-up.

To clarify for future readers how these concepts map onto Hugo page variables, given URL:

The .Permalink would be:

And the .RelPermalink would be:


And that’s the problem: the naming. .RelPermalink is in fact an absolute URL from the root of the website. I’ll have to find a way to point that out. Maybe I’ll use URL instead of link as the term and then when using Hugo samples the link as a term.

Yes, the naming is unfortunate. RelPermalink is a relative reference with an absolute path, which I think is where the confusing name comes from.