Jekyll’s site.url and baseurl
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 as seen above.
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 website: https://mademistakes.com
website: 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.
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:
- Double forward slashes e.g.,
//minima/assets/style.css
- Missing base URL due to not using
relative_url
filter,absolute_url
filter, or{{ site.baseurl }}
in theme files.
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
orhttp://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
.
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
.Posts follow standard naming conventions of
YYYY-MM-DD-filename.md
inside of a_posts
directory.Image assets are in a
images
directory inside of the root.Have the following
_config.yml
settings:website: https://mmistakes.github.io basewebsite: /blog permalink: date
Markdown links
How to link to pages, posts, and images in Markdown.
Page in root directory
[about page](/about.html)
HTML output | - |
---|---|
<a href="/about.html">about page</a> URL is missing the base URL of /blog from the path. | ❌ |
Page in sub-directory
[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> | ✅ |
Page in date sub-directories
[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> | ✅ |
Image in root directory
[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. | ❌ |
Image in sub-directory
[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"> | ✅ |
Root-relative URL links
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"> | ✅ |
Absolute URL links
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!
4 comments
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.
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.
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 removebasewebsite: /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 addbasewebsite: /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 onlypage.url
.