Need help understanding url conversions


I’m struggling to understand how URLs are changed by the likes of absURL or relURL.
(it’s a lot like, but it seems that that was not resolved)

in my config.toml I have:
baseurl = “

background = “/images/background.jpg”

I expect hugo (using 0.17) to process {{ .Site.Params.background | absURL }} to, but it doesn’t :frowning:

I want to use a deploy script to deploy several sites to a single toplevel url under their respective names, in order to test an arbitrary amount of sites using hugo. When the site goes to production, the baseURL is changed to something like “

prepending {{ .Site.BaseURL }} does seem to work, but isn’t this an ugly workaround? From the comments on the other post, it probably won’t work with markdown content/metadata urls…

Either I don’t understand it, or I guess this a bug in how baseurl is used. Please enlighten me :wink:



  • /images/foo.jpg is an URL relative to server/host root – all browsers in the world should agree with me on this
  • you may want to use images/foo.jpg (which may not be according to spec, but the only thing that made sense for Hugo)
  • See for all the variations

I guess I’m just confused then :-/

In html links (the generated site) I agree with you about /images/foo.jpg being an absolute URL. However what confuses me is the use of relative urls in e.g. posts, or layout templates. Is it relative to the baseURL (always? regardless of where the markdown file or template file is located?). In that case I think I can figure it out…

BUT absolute urls like /images/foo.jpg are only relevant to the toplevel of where the static site is located and as such, it is weird that with a baseURL of http://foo/bar/ it would be translated to http://foo/images/foo.jpg, because as far as hugo is concerned, nothing exists above the baseURL?

Back in the old days (the '90’s , the home of netscape and static html :wink: it was considered bad practice to use absolute paths in links/image tags, because then you couldn’t move the pages around. Given that all hugo does is generate static html, I expected it should also adhere to best practice from that era…

What would be the usecase of having baseURL with a path element ( and an “absolute” path go from the toplevel and ignore the path element (/bla)?


I don’t understand what you are talking about, so you should shorten it and maybe add some examples of what you expect.

I have been doing web development since the 90s, so I think I understand the magic of URLs, but one never knows …

I guess the confusion starts with the need for baseURL in the first place. If all links generated by hugo are relative to the current page, the end result (the site generated in public/) should not care where it lives; on the filesystem, at the toplevel of an url or somewhere a few levels down. I would upload the contents of public/ to

but it would also work just as well under

I guess the need for baseURL comes if you don’t want lots of links with …/…/ in it :wink:

So if I define a variable in the frontmatter with “/images/someimage.jpg” I expect to get a url that works regardless of where the site is located.
baseurl = http://x.y/z/

an image defined with “/images/someimage.jpg” in /content/project/ should work, at least relative to the baseURL, but more optimally it should work relative to wherever the generated html file is placed.
This doesn’t seem to be the case right now.

(I’m using hugo 0.17 and theme HugoMDL)

there’s a variable cardthumbimage = “/images/img.png”

If the baseURL contains a path element, this doesn’t generate a valid url, but if I use cardthumbimage = “…/images/img.png”, which is weird, because then it doesn’t work anymore when I add or remove a path element from the baseURL.

I want to have my content markdown files to be agnostic about where the resulting html is going to be located.

Hopefully this makes it more clear what I want/expect or what I’m doing wrong :wink:



My first answer explains what’s needed to get correct absolute URLs via the absURL funcs. There is also the relURL func with similar semantics.

This is too big a question for me to explain – but I sense you have a fairly naive approach to the question.

Any problems with a theme in this area, please take this up with the theme author.

I understood the reference to the tests and they make it quite clear what hugo expects to do with the URL when filtered through absURL or relURL. But as you mention the theme author, the problem I’m looking at could be a confusion of standard hugo and the theme implementation. I’ll see if I can figure out what I should do or ask the theme author to get closer to a fix…

However I also think my “ideal” about a completely relative site isn’t (yet) possible with hugo :wink:

Thanks for your efforts to help me understand, despite my naive approach :stuck_out_tongue:
(I’m not usually a webdeveloper, but more of a sysadmin these days…)

See for REAL relative URLs.

That’s what I meant :smile:
I think I tried that once, but not correctly, perhaps…

There are multiple uses: your ld+json (and other) metadata for SEO, canonical URL, prefetch/prerender/preconnect…

Check your config.toml for the relativeURLs value and refer to the link provided by bep.

@rdwatters, I’m sorry, I’m more confused by your words than I was before :wink: (I don’t understand ld+json, SEO prefetch/prerender/preconnect in this context :frowning: )

I’m starting to think it may be the theme (HugoMDL) which doesn’t work with relativeURLs in all cases. I tried the examplesite and the relative links do work in some cases, but not in others.
Specifically, in places where background-image is set in a template using:

<body style="background-image: url('{{ .Site.Params.background }}');">

This url will not be translated to a relative url and I know this kind of usage happens in a few places in the templates of HugoMDL

I’m way to unfamiliar with the internals of hugo or themes to know where the problem should be solved (theme or hugo). Are there other themes where this does work well?



If that code you just added is directly from your theme, you should be able to add the name of the image file in your config file. This can include whatever path you want as well. For example, I keep my default social image at “/assets/images/default-social-image.jpg”). To use it in the above code, I would just set my config.toml file to "background = “/assets/images/default-social.jpg”. This means it’s always going to pull from the root of the site. That said, I have no idea how your source is organized, -!: the example you gave is technically inlined CSS, not HTML, so I’m not sure how Hugo is going to handle this. Images and separate directories is also a common topic and feature request for Hugo too, so you might want to dig around the forums a little more. As for relative paths, etc…I can see how you might be confused, but don’t despair: the great thing about hugo is that it’s been built to make the fewest assumptions possible about how you want to organize your source.

The background image is indeed set in the config.toml and it is “/images/background.jpg”.

Unlike the links produced by hugo from the markdown files, this link is not processed to become a relative link when relativeURLs is set to true.

So when I place the entire generated site under a subdir, some links still work (relative links) and this type of link breaks, causing the site to look horrible without background images (for the page, but also for some divs in the various articles and other elements).

The question I’m trying to figure out is whether there is a better way to code this, so that hugo knows how the link to the background image is supposed to made relative too…
And at the same time, I’m wondering if this might just be a bug. Maybe hugo is coded to only relativize urls in hrefs, not other valid places that may contain a url?

Why has this not bothered other people before? Basically I took the exampleSite of HugoMDL and just switched on relativeURLs, How do other people test a whole bunch (arbitrary number) of hugo sites? Or do most people just work on one site and always at toplevel? (Please note that this is something I imagined to be doing, I don’t have more than a few sites to test yet, just starting to build up a workflow for it…)

I’ve taken a look now at the demo on the themes page under the Hugo docs. I think it would be good to post an issue in the GitHub repo for HUGOMDL or just contact the theme developer via

Since this is inlined css, why not just add the baseurl the way you mentioned in your first comment (this isn’t an “ugly workaround”)? Adding {{.Site.BaseURL}} in this case is for your templates, not the markdown files, so I’m confused about why you mentioned it previously in the thread.

In your config, I would just do the following:

  background = "background.jpg"

Then in the template above, prepend with your base URL…

<body style="background-image: url('{{.Site.BaseURL}}/images/{{.Site.Params.background}}');">

Then make sure that background.jpg is housed in static/images/background.jpg. I’m not sure how this repeat reference to a single image would break across multiple pages.


This type of image inclusion (using the background of an element) is used in other places as well, like in an overview page with content from markdown files. So this example is one of several.

You suggestion to use .Site.BaseURL to form the url doesn’t help in the case of relative urls, since it generates an absolute link regardless of how relativeURLs is set.

I’ll start an issue on the github repo for HugoMDL…

BTW, anyone know of a proper solution to fix this?

I created an HugoMDL issue

But I also figured it could be fixed in hugo
look in hugo sources: transform/absurlreplacer.go

 60 // new prefixes can be added below, but note:
 61 // - the matches array above must be expanded.
 62 // - the prefix must with the current logic end with '='
 63 var prefixes = []*prefix{
 64         {r: []rune{'s', 'r', 'c', '='}, f: checkCandidateBase},
 65         {r: []rune{'h', 'r', 'e', 'f', '='}, f: checkCandidateBase},
 66         {r: []rune{'s', 'r', 'c', 's', 'e', 't', '='}, f: checkCandidateSrcset},
 67 }

it could be fixed in hugo to also process urls in css when abs or rel URLs are requested.
I don’t know how much work this is, it seems there’s a limit to links after something ending with “=” in the current logic.

It would also need to process urls inside url(’ ') links in the style element.


I’m curious as to why you feel this feature is so important since it a) has to do with style (Hugo is only interested in your markup/content, which is I think it’s greatest strength) and b) all images are currently part of static/, which gets copied over as is.

Nevertheless, I think reaching out to the theme’s creator isn’t a bad idea, but the “fix” I gave above isn’t a workaround. It will work. And again, it’s only pointing to a single image, which is going to live in a single place since it’s copied over as-is from the static folder. It’s also part of the template and not the copy being created by an author and is (in the example you provided from this specific theme) used on every page as the background. This is a drawback of using CSS to place images rather than using a src in an <img> tag, which Hugo already takes care of very easily w/r/t relative URLs.

To me it’s important, because it would fix my problem and I think in a more generic sense, it would allow a generated site to be placed anywhere.

Your fix will work, but only when you place the site in the place specified by config.toml/baseURL, it can’t be moved later on…

This type of image use is not just in the body element, but also in other places like divs with other images whose URL is specified in the markdown frontmatter.

If I or Jeremy or anyone comes up with a fix for the theme HugoMDL that doesn’t rely on style to place images, That would be very welcome…

I’m confused – why are you starting your relative URLs with a slash if you want them to be relative to an arbitrary base?

What happens if you remove the leading slash and use URLs of the form images/someimage.jpg instead? From the docs that @bep linked, I assume that would work. It should treat images as a directory to append to the base or current content.

A leading slash is universally interpreted as an absolute URL, which is relative to host (to clear some potential confusion, yes, many people use the term “absolute” URL to mean a fully qualified URL, which is a full-length URL starting with the scheme/protocol). Even when you use the <base> element in an HTML page, if you subsequently use a leading slash in a “relative” URL, it will only be relative to the host, not the URL you set in your <base> tag. I think you can get the behavior you want if you just omit the leading slash.

Who is this question for, @JoeWeb? This is concerning inline CSS.