October 23, 2017

Setting Development Variables in Jekyll

Over the last few months I’ve been making some minor adjustments to this site, and the Back to Front Show site, both of which run on Jekyll. One thing I have found really useful is having the ability to chain multiple config files together — especially when developing locally.

Using Variables

I currently use Cloudinary to serve blog post images. I plan on writing a bit more on the “why and how” of using Cloudinary in another post but essentially when developing locally the Cloudinary based URLs will only work if the original image has been made available online. Cloudinary uses an origin-pull method to add images to it’s own network and therefore has no knowledge of new images that aren’t available via a public URL.

When adding a new post I create images locally and add them to a folder within my Jekyll site — which are then available locally for preview. Once the post is complete I push the images and markdown file to GitHub which regenerates the site. However, given that my figure element include file (below) references Cloudinary I am unable to preview the images during a local preview as Cloudinary has no concept of the image stored on my local machine. Previewing locally only results in a 404 error on any image referencing the Cloudinary URL.

    <img sizes="100vw" src="https://res.cloudinary.com/keirwhitaker/w_auto:250:400,f_auto/remote/posts/{{ include.url }}" alt="{{ include.alt }}" />
    <figcaption class="{{ include.class }}">{{ include.caption }}</figcaption>

After some head scratching I came across the option of chaining multiple config files together. This option allowed me to make use of a single config variable that is loaded in for local development and can be used to change the logic within the templates to load the images locally.

It’s actually pretty simple to implement. In _config.yml I created a variable called environment and defined it as follows:

environment: production

This is the default config file that GitHub will use when building the site so it should reflect our production settings. Next I created a new .yml file called _config.dev.yml and saved it in the root of my Jekyll project. It also contains a definition for the environment variable, this time set to development:

environment: development

In effect this is simple overriding the setting in the main config file. This variable then allows me to run a simple if statement in my figure include as follows:

    {% if site.environment == "development" %}
    <img sizes="100vw" src="/img/posts/{{ include.url }}" alt="{{ include.alt }}" />
    {% else %}
    <img sizes="100vw" src="https://res.cloudinary.com/keirwhitaker/w_auto:250:400,f_auto/remote/posts/{{ include.url }}" alt="{{ include.alt }}" />
    {% endif %}
    <figcaption class="{{ include.class }}">{{ include.caption }}</figcaption>

Simply put if the environment variable equals development then the site will be built using my local image path, if not then it will use the Cloudinary URL.

All good in theory but how to put it into practice. The “magic” happens when starting Jekyll from the terminal. Using Bundler I normally fire up Jekyll as follows:

bundle exec jekyll serve

In order to chain our config files together we need to add in the --config flag as follows:

bundle exec jekyll serve --config _config.yml,_config.dev.yml

--config takes a comma separated list of filenames as it’s argument. In the example above I am loading our base config file followed by the config file containing the variable override.


I’ve been using the above method quite happily but there’s also another, perhaps you could argue the “proper”, way of achieving the same result.

It’s also possible to specify a Jekyll environment value when building or serving a Jekyll site. This will then be available to use in conditional statements in your code.

The Jekyll docs use the following example:

{% if jekyll.environment == "production" %}
   {% include disqus.html %}
{% endif %}

When firing up your Jekyll site (using build or serve) the above statement will only run if the environment value has been passed in.

In order to pass it in using serve and Bundler you need to prepend it to the beginning of your command:

JEKYLL_ENV=production bundle exec jekyll serve

It’s worth noting that he default value for JEKYLL_ENV is development. Therefore if you omit JEKYLL_ENV from the build or serve arguments, the default value will always be JEKYLL_ENV=development.

Using this approach you can avoid having to change value in your configuration files but it has the exact same end result as using chained config files.

This article was written by Keir Whitaker and published on October 23, 2017. All articles are available in the blog archive and you can subscribe to the RSS Feed for updates. Have a question? Discuss this article with me by email.