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.
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!"
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.
How to use url and baseurl
A couple of important facts to keep in mind when using both:
Leave off trailing forward slashes when setting url
✅ Do this
❌ Don’t do this
url: https://mademistakes.com
url: https://mademistakes.com/
baseurl is not needed for most sites and can be omitted.
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:
Missing base URL due to not using relative_url filter, absolute_url filter, or {{ site.baseurl }} in theme files.
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.
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.
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:
Jekyll v4.2 or greater is installed.
The site is hosted on GitHub Pages in a sub-directory named blog.
[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
-
<ahref="/blog/2021/06/29/welcome-to-jekyll.html">Welcome to Jekyll post</a>
✅
[cheese pizza](pizza.jpg)
HTML output
-
<imgsrc="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
-
<imgsrc="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
-
<imgsrc="/images/pizza.jpg"alt="cheese pizza"> URL is missing the base URL of /blog from the path.
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.
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.
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.
Michael Rosewrote 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.
You saved my day! This piece of code is the answer for the problem I tried to solve for couple of days: {{ page.url | prepend: site.baseurl | prepend: site.url }}
I just leave it here, that it also works with post.url, not only page.url.
Interactions
4 comments
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.
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 tocss: <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.
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.
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 runningjekyll serve
locally, then you can completely removebaseurl: /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 addbaseurl: /blog
when building your Jekyll site.Irina Ivanova wrote on
You saved my day! This piece of code is the answer for the problem I tried to solve for couple of days:
{{ page.url | prepend: site.baseurl | prepend: site.url }}
I just leave it here, that it also works with
post.url
, not onlypage.url
.