Jekyll’s site.url and baseurl

Learn what Jekyll’s site url and baseurl variables are and how to properly set them with relative_url and absolute_url filters to avoid broken links and 404 errors.

Last updated on
9 min read
On this page

Jekyll’s site url and baseurl variables cause a lot of confusion for users. I see it all the time in the Jekyll Talk forum, Stackoverflow, or as bug reports in my themes.

My Jekyll site works locally but when I push it up to GitHub Pages it is broken with no styling and looks like this. Help!"

Jekyll Minima site with missing CSS

Improper use of Jekyll's baseurl can break links to CSS, posts, and more.

What are url and baseurl?

So what exactly are the url and baseurl variables? To start, both are site-wide variables set in the _config.yml file and affect how Jekyll builds URLs. I like to describe them like this:

Site variable Description
url A site’s full URL including protocol, domain, and port (if applicable).
baseurl Name of sub-directory the site is served from e.g., /blog.

illustration describing site url and baseurl permalink structure

How to use url and baseurl

A couple of important facts to keep in mind when using both:

  1. Leave off trailing forward slashes when setting url

    ✅ Do this ❌ Don’t do this
    url: https://mademistakes.com url: https://mademistakes.com/
  2. baseurl is not needed for most sites and can be omitted.
  3. baseurl is only necessary when hosting your site in a sub-directory. Project sites hosted on GitHub Pages are the common use-case of this variable.
Remember to properly set links

These URL variables are not magic and need to be applied to links in your layouts, includes, or themes. This can be done by prefixing all links with {{ site.url }}{{ site.baseurl }} or by apply Jekyll’s absolute_url or relative_url filters to them.

Jekyll URL troubleshooting

If we go back to the example above with the broken CSS link and inspect the HTML’s source. You will often find that the link to the CSS file is incorrect for any number of reasons:

  1. Double forward slashes e.g., //minima/assets/style.css
  2. Missing base URL due to not using relative_url filter, absolute_url filter, or {{ site.baseurl }} in theme files.
Firefox web inspector showing HTML source and broken stylesheet reference

When the path to the stylesheet is wrong the browser can’t load it. No stylesheet == plain looking website with no styles and looks broken.

Jekyll development and site.url

One other question I see asked over and over again from Jekyll users is:

Why are my links broken? They all start with http://localhost:4000 or http://127.0.0.1:4000.

Screenshot of GitHub Pages default 404 file not found page

This happens because in older versions of Jekyll (v3.3 through 4.1) it would reset site.url to localhost:4000 when JEKYLL_ENV=development (the default environment value), overriding whatever is set in the _config.yml. In newer versions of Jekyll (v4.2 and up) this reset of site.url no longer happens.

In older versions of Jekyll, site.url is also reset to http://localhost:4000 when spinning up a development server with the jekyll serve command.

site.url values

Jekyll version Environment CLI command site.url value
4.2 (✨latest) development serve value set in _config.yml
3.3 development serve reset to http://localhost:4000
4.2 (✨latest) development build value set in _config.yml
3.3 development build value set in _config.yml
4.2 (✨latest) production serve value set in _config.yml
3.3 production serve value set in _config.yml
4.2 (✨latest) production build value set in _config.yml
3.3 production build value set in _config.yml

Under normal circumstances these two conditions won’t cause any headaches, especially when hosting on GitHub Pages as the environment and url are set automatically.

The issue surfaces when building locally, using an older versions of Jekyll, and then forgetting to set JEKYLL_ENV to production. Or pushing up files from a _site directory after running jekyll serve instead of jekyll build.

⚠ GitHub Pages dependencies and versions

Further confusing the issue, GitHub Pages does not use the latest version of Jekyll to build sites. It is currently locked at 3.9.0, which means it doesn’t have parity with a lot of the new hotness found in version 4.

Examples

Below you will find examples of how to write different types of links that require site.url or site.baseurl values to work properly. Links marked as ✅ have valid URLs while those marked as ❌ are broken and will trigger a 404 file not found error.

Each of the examples assume:

  1. Jekyll v4.2 or greater is installed.
  2. The site is hosted on GitHub Pages in a sub-directory named blog.
  3. Posts follow standard naming conventions of YYYY-MM-DD-filename.md inside of a _posts directory.
  4. Image assets are in a images directory inside of the root.
  5. Have the following _config.yml settings:

    url: https://mmistakes.github.io
    baseurl: /blog
    permalink: date

How to link to pages, posts, and images in Markdown.

[about page](/about.html)
HTML output -
<a href="/about.html">about page</a>
URL is missing the base URL of /blog from the path.
[about page](/blog/about.html)
[about page]({{ site.baseurl }}/about.html)
[about page]({{ 'about.html' | relative_url }})
HTML output -
<a href="/blog/about.html">about page</a>
[Welcome to Jekyll post](/blog/2021/06/29/welcome-to-jekyll.html)
[Welcome to Jekyll post]({% post_url 2021-06-29-welcome-to-jekyll %})
[Welcome to Jekyll post]({% link _posts/2021-06-29-welcome-to-jekyll.md %})
HTML output -
<a href="/blog/2021/06/29/welcome-to-jekyll.html">Welcome to Jekyll post</a>
[cheese pizza](pizza.jpg)
HTML output -
<img src="pizza.jpg" alt="cheese pizza">
URL is missing the base URL of /blog and sub-directory /images from the path.
[cheese pizza](images/pizza.jpg)
HTML output -
<img src="images/pizza.jpg" alt="cheese pizza">
URL is document-relative when it should be root-relative and is missing the base URL of /blog from the path.
[cheese pizza](/images/pizza.jpg)
HTML output -
<img src="/images/pizza.jpg" alt="cheese pizza">
URL is missing the base URL of /blog from the path.
[cheese pizza](/blog/images/pizza.jpg)
[cheese pizza]({{ '/images/pizza.jpg' | relative_url }})
[cheese pizza]({{ site.baseurl }}/images/pizza.jpg)
HTML output -
<img src="/blog/images/pizza.jpg" alt="cheese pizza">

How to link resources with root-relative URLs, like stylesheets, favicons, and JavaScript.

<link rel="stylesheet" href="/assets/css/style.css">
HTML output -
<link rel="stylesheet" href="/assets/css/style.css">
URL is missing the base URL of /blog from the path.
<link rel="stylesheet" href="/blog/assets/css/style.css">
<link rel="stylesheet" href="{{ site.baseurl }}/assets/css/style.css">
<link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
HTML output -
<link rel="stylesheet" href="/blog/assets/css/style.css">

How to link to resources that require the full URL, like a canonical URL in the page’s <head>.

<link rel="canonical" href="{{ page.url }}">
HTML output -
<link rel="canonical" href="/2021/06/29/welcome-to-jekyll.html">
URL is missing the site URL and base URL of /blog from the path.
<link rel="canonical" href="{{ page.url | absolute_url }}">
<link rel="canonical" href="{{ page.url | prepend: site.baseurl | prepend: site.url }}">
<link rel="canonical" href="{{ site.url }}{{ site.baseurl }}{{ page.url }}">
HTML output -
<link rel="canonical" href="https://mmistakes.github.io/blog/2021/06/29/welcome-to-jekyll.html">

As you can see from above examples, Jekyll is flexible and allows for multiple ways of creating links. Personally I tend to lean on the relative_url and absolute_url filters as they require less typing and have some “smarts” to them.

The best option is the one that works for you!

About the author

Hi I’m Michael Rose. Just another boring, bearded, tattooed, time traveling designer from Buffalo New York. I maintain several open source projects and occassionally blog.

Glitched photo of Michael Rose with a long beard.

Interactions

3 comments

  1. Kat wrote on

    This post saved my life.

    THANK YOU, from a cheap musician building her own portfolio with limited experience. The urls were driving me crazy and now they aren’t. I love it when everything just works.

  2. Dalibor Pavlík wrote on

    Good article. But still, there is something that I am missing. This is an example.

    I have this baserul: /blog This is my path to css: <link rel="stylesheet" href="{{ site.baseurl }}/css/pages-style.css">

    I develop locally and run jekyll serve. When I inspect the page, this what I see in the head of the page.

    <link rel="stylesheet" href="/blog/css/pages-style.css">

    But why? Why does jekyll inject the baseurl locally. It does not need to be there locally. It need to be there when I deploy the page on github. Correct? It just does not make sense to me.

    Anyway, thank you for the article. It summarizes the issues well. But still, I am puzzled. I will probably be adding the site.baseurl to config file just before deployment.

  3. Michael Rose wrote on

    It adds the baseurl because it is helpful to know that your file paths will be correct or not. Jekyll is emulating how the file paths would need to be when your site is uploaded to /blog.

    If it stripped /blog from the URLs then you wouldn’t know if you had bad paths or links prior to pushing up to GitHub to host on Pages.

    If you really don’t want to see /blog in your paths when running jekyll serve locally, then you can completely remove baseurl: /blog from your _config.yml file. GitHub Pages automatically adds that value based on the repo and type of site (user or project site).

    For example if you have a repo named blog it would be a project site and GitHub would automatically add baseurl: /blog when building your Jekyll site.