We're live-coding on Twitch! Join us!

Jekyll is a simple and blog-aware static site generator built in Ruby. In laymen terms, it's just a tool to let you have all the cool features of a full-blown CMS without having to worry about managing a database. This means hosting is extremely easy and scalable since all you're doing is managing a bunch of files.

In this tutorial, we'll cover everything you need to know to get started. It doesn't matter if your a seasoned Ruby developer or have never written a line of Ruby in your life. We'll also walk-through some best practice approaches and provide you with an awesome free starter Jekyll theme with Bootstrap 3 for you to fork and repurpose.


You can check-out a demo the blog we're building here or dive straight into the theme's code here. Our starter theme should be helpful for several reasons:

  • Bootstrap 3 integrated
  • Organized global variables
  • All config settings setup
  • Pages setup in their own folder
  • Simple BS3 pagination demo
  • Dead simple layout simple
  • .gitignore already setup
  • Multiple post options: Featured Image, Video, Lead Text, etc.
  • Category and tag integration
  • Huge, in-your-face, blog-style you can easily change (accepting pull requests)

Jekyll Benefits


Jekyll is really flexible. You can build templates and write content in markdown, textile, liquid, or even just plain HTML/CSS. It really doesn't matter and is up to your preference because Jekyll will intelligently build your site based on all your files.


The entire website gets compiled into a static website. This means you can host it in almost any server environment with nearly zero overhead. You can also host it for free on Github Pages, or host it on a file storage service like Amazon S3. Finally, since it's static, if you put any sort of CDN with HTML caching (CloudFlare, CloudFront, etc.) in front of it, you'll sleep well at night knowing you can very cheaply handle an almost unlimited amount of traffic without downtime.


Jekyll has all the benefits of a CMS, you just need to know how to use it. It's completely blog-aware with permalinks, categories, pages, posts, custom layouts, and even custom content types called Collections. On top of this, there's themes, plugins, and all sorts of extras.

System Requirements


Now that we have done a very healthy intro into Jekyll, let's get started!

Jekyll is a command-line executable built with Ruby and has a few commands we need to run from time to time. If you're not a Ruby developer, there's a few things we need to do to setup our environment for this kind of development.

We'll be doing this tutorial for Mac users, but it's very similar to Windows (Window users see this resource first) and Linux users.

The first thing you want to do is make sure Xcode Command Line Tools is installed.

Run this command from your terminal to start the download prompt:

xcode-select --install

The next thing you need to do is install Ruby. Your system might already have this, but we'll be getting the latest version. First install Homebrew:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

If you already have Homebrew install, first update it with:

brew update

Next, install Ruby by following these steps:

brew install rbenv ruby-build

# Add rbenv to bash so that it loads every time you open a terminal
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile
source ~/.bash_profile

# Install Ruby
rbenv install 2.2.2
rbenv global 2.2.2
ruby -v

If you're using oh my zsh, make sure you add this to the bottom of your ~/.zshrc file or you still won't be using the most current version of Ruby we just installed:

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

At this point, you should have the latest version of Ruby installed. You'll also notice RubyGems (Ruby's package manager) was installed.

You can see that with:

gem -v

You can update RubyGems with:

sudo gem update --system

For whatever reason if RubyGem's isn't installed, follow the manual install instructions here.

Finally, it's a good idea to install Bundler even though we won't be using it for this tutorial. Bundler allows a way to make sure that different gems have matching versions across different systems. This is especially useful while collaborating with teams.

It's really similar to how Composer or how NPM manages dependencies:

sudo gem install bundler

The last requirement is to make sure you have NodeJS installed. If you don't have it installed yet, just run:

brew install node

This might seem like a lot, but is a pretty standard setup for a lot of web developers. Plus, now your machine is Ruby ready!



Now that you have all your system requirements setup, installing Jekyll is as easy as:

gem install jekyll

If you run into permission issues, just do:

sudo gem install jekyll

After Jekyll is done installing, you should be able to type anywhere from the command-line:

jekyll -v

This will prompt you with the Jekyll version installed and means Jekyll is successfully installed.

Getting Started

Before we kick-off on building our blog, I quickly wanted to note how awesome the Jekyll documentation is and recommend checking it out.

So let's spin-up our first blog. From the command-line, navigate you where you'd like this project to be and type the following command:

cd wherever/you/want/this/project/on/your/computer
jekyll new my-blog


The new command here will create an install of Jekyll with the default theme. Alternatively, if you'd rather start with our theme, run the following command instead (Note: We make a ton of comparisons in this tutorial to the default theme setup in this tutorial. It might be a good idea to follow along that way first.):

git clone https://github.com/scotch-io/scotch-io.github.io my-blog

Let's jump into our new my-blog directory and run the serve command:

cd my-blog
jekyll serve

Jekyll comes with a built-in development server. This command start this server on your machine and starts watching your files for changes similar to Grunt or Gulp. This is awesome and makes development super easy with little overhead on your part.

Now navigate to in your browser to see the Jekyll install we just setup.


Let's quickly explain some commands and how Jekyll works a bit more. Since there's no database, you're going to be creating new pages, posts, and templates in markdown, html, textile, or liquid files and then using Jekyll to compile (or build) them together into a website. Before building the site, it actually doesn't exist and is just a bunch of template files.

"serve", or just "s"

The serve command builds your site, boots up a development server, and starts watching files for changes by default. Any time a change happens, it will build your site automatically (see below).

To run this, just do:

jekyll build

Stopping the server is as easy as:


"build", or just "b"

By default, whenever you build your website, it will be generated into a folder called _site.

You can generate your static site by running:

jekyll build

You can also change the destination with:

jekyll build --destination <destination>

Lastly, you can also add a --watch flag to rebuild on changes:

jekyll build --watch

Your probably wondering why you wouldn't just use the serve command. This is useful to know for serveral reasons:

  • You don't always want the local server.
  • It's best practice to .gitignore your _site folder. So you may have to just compile your site on the fly somewhere.


The new command will create a new Jekyll site scaffold in PATH (aka, the current location) with the default theme. We did this already while getting started.

Here it is again:

jekyll new my-new-static-super-cool-blog-about-cats-and-dogs

You'll only have to do this when starting a new project from scratch. If you're using a theme or existing site, you won't even touch this.

Folder and Directory Overview

So we created our first project and are now familiar with the commands a bit. Let's review the folder structure that was created with the new command.

It's important to learn these pieces well since this is essentially the core framework of Jekyll, its templating, configuration, and where content generation is done.

We're just going to do a brief overview of these and jump into all of them in detail later in the tutorial.

You can also reference the official Jekyll docs on Directory Structure.


If you're starting a new project or cloning down an existing one, this is usually the first file you'll want to take a peak at. This file hosts global configurations for your entire site in YAML format.

These configurations are defaults used by the jekyll executable (such as a destination) and can also be retrieved in templates or content by doing:

{{ site.variable_name }}

We'll cover this in a lot more detail in a bit. Here's the official resource on Jekyll config if you want to quickly review.


We'll cover how layouts work later too, but this directory is where you will put your templates. Templates are the HTML that wrap posts and other types of content like pages.


This folder is where you'll put reusable bits of code for your templates. This is sometimes also called "partials" or "slices". We'll cover how to use these in the templating section later too.


This folder contains all your posts in a format of your choosing. Since there's no database, each post is a separate file formatted like so:



You'll notice this folder actually isn't there if your using the default theme! You can create this empty folder now, but this is just where you will store unpublished posts.


This also doesn't exist yet with the default theme! You can add this in case you want to add plugins later.


The default theme comes with this page in the root directory. This is slightly annoying for organizational purposes. In the Scotch Theme though, we moved this to it's own folder _pages. We'll cover that later.


This is your blog's homepage. So long that this file has a YAML Front Matter section (which, again, we'll cover), it will be transformed by Jekyll. The same will happen for any other .html, .markdown, .md, or .textile file in your site’s root directory or directories not listed above.


This is your generated static website. Everytime your site is built or generated, this folder is "cleaned" and rebuilt from scratch. So never touch this and just know that it exists solely to host the output of your static site.


This is where you'll host things like reusable data, variables, or more. We'll make extensive use of this folder. Data can be in YAML, JSON, or a CSV.


Jekyll comes Sass-ready. The default theme doesn't use Bootstrap, but you can compare it to the Scotch Theme on how we integrated Bootstrap 3 with it.

Any Other Files/Folders

All other files and folders automatically get copied over to the static generated site. So if you create a folder called img, it will be copied over to the static site. This makes referencing images easy.

You'll notice that with the Scotch Theme, we created a js and img folders since the default theme doesn't have these out-of-the-box.


As mentioned above, your site's configuration is done in _config.yml. The values set here are shared to the jekyll command from the command-line.

You'll also notice in the default theme that there's some settings in the example generated such as email, twitter_username, and github_username. Some people use this for declaring site-wide global variables since you can retreive them in templates like so:

{{ site.variable_name }}

Although you can do this and the default theme does this, I actually recommend using Data Files for anything custom instead.

When developing, Jekyll will not watch this file for changes. Any changes only happen during a brand-new site build - which is midly frustrating when moving fast.

That's why it makes sense to limit this file to your build config only. So what we did with the Scotch Theme was actually delete everything and add every single default value for quick reference and tweaking instead.

This is a full list of all the defaults:

# Where things are
source:      .
destination: ./_site
plugins:     ./_plugins
layouts:     ./_layouts
data_source: ./_data
collections: null

# Handling Reading
safe:         false
include:      [".htaccess"]
exclude:      []
keep_files:   [".git", ".svn"]
encoding:     "utf-8"
markdown_ext: "markdown,mkdown,mkdn,mkd,md"

# Filtering Content
show_drafts: null
limit_posts: 0
future:      true
unpublished: false

# Plugins
whitelist: []
gems:      []

# Conversion
markdown:    kramdown
highlighter: rouge
lsi:         false
excerpt_separator: "\n\n"

# Serving
detach:  false
port:    4000
baseurl: "" # does not include hostname

# Outputting
permalink:     date
paginate_path: /page:num
timezone:      null

quiet:    false
defaults: []

# Markdown Processors
  extensions: []

  extensions: []

  auto_ids:       true
  footnote_nr:    1
  entity_output:  as_char
  toc_levels:     1..6
  smart_quotes:   lsquo,rsquo,ldquo,rdquo
  enable_coderay: false

    coderay_wrap:              div
    coderay_line_numbers:      inline
    coderay_line_number_start: 1
    coderay_tab_width:         4
    coderay_bold_every:        10
    coderay_css:               style

If you'd like to read more about configurations, check the official docs on it here.


Templating in Jekyll is amazingly simple. If you're familiar with modern templating systems, it will be a breeze to learn.

Templating is basically broken down into two parts: Front Matter and Liquid Templates

Front Matter

Front Matter is YAML located at the top of your files for specifying page or template specific variables. This is where the beauty and power of Jekyll comes from.

An example of Front Matter on a page would be:

layout: page
title: About
permalink: /about/

# {{ page.title }}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et eros pretium, tristique orci a, pharetra elit. Phasellus tincidunt viverra urna at placerat. Etiam et urna at purus pellentesque tempor.

## Heading 2

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et eros pretium, tristique orci a, pharetra elit. Phasellus tincidunt viverra urna at placerat. Etiam et urna at purus pellentesque tempor.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et eros pretium, tristique orci a, pharetra elit. Phasellus tincidunt viverra urna at placerat. Etiam et urna at purus pellentesque tempor.

On a site build, Jekyll will parse this information at the top, generate a page accessible at the URI "/about", and make sure it uses the layout that is named "page".

And, as the example above shows, you can also access front-matter variables with liquid by doing:

{{ page.variable_name }}

Front Matter variables can override defaults or be totally custom. For a full list of the defaults, reference the official docs here.

Liquid Templates

Jekyll uses the very awesome Liquid Templating Language by Shopify. It's easy to learn, secure, and extremely extensible.

The fastest way to get aquanted with Liquid is to read this resource: Liquid for Designers. It covers everything and more. We'll cover the basics here too though very quickly.


These go in a folder called _includes. Here's the syntax:

{% include my-include.html %}

Echoing or Printing

{{ variable_name }}

Tag Markup (doesn't print)

{% stuff goes here %}


{{ 'i am now uppercase'|upcase }}


{% for post in posts %}
    My title is {{ post.title }}
{% endfor %}


{% if variable_name %}
    variable_name exists
{% else %}
    variable_name doesn't exist
{% endif %}

Creating Pages

Creating pages with Jekyll is as easy as creating a new file. By default, you can just create the file in your root directory, but we'll be organizing our pages in their own folder.

To do that, all you need to do is add this to your _config.yml. Remember to reboot your local environment afterwards:

include: ['_pages']

Then, just create a file that is either .html, .markdown, .md, or .textile and add your front matter. Your front matter can be any variables you want, but you need to pick a layout, title, and permalink at minimum.

Here's an example:

layout: inner
title: About
permalink: /about/

It doesn't matter what comes, fresh goes better in life, with Mentos fresh and full of Life! Nothing gets to you, stayin' fresh, stayin' cool, with Mentos fresh and full of life! Fresh goes better! Mentos freshness! Fresh goes better with Mentos, fresh and full of life! Mentos! The Freshmaker!

We got a right to pick a little fight, Bonanza! If anyone fights anyone of us, he's gotta fight with me! We're not a one to saddle up and run, Bonanza! Anyone of us who starts a little fuss knows he can count on me! One for four, four for one, this we guarantee. We got a right to pick a little fight, Bonanza! If anyone fights anyone of us he's gotta fight with me!

Creating Posts

Creating posts are equally easy as creating pages. The only difference is you need to associate a date or timestamp with them and they go in their own folder:


Here's how you should create your file:


This is automatically parsed by Jekyll and creates default title and date variables. You can override this in your front-matter though. Here's an example of a post's front-matter:

layout: inner
title: 'My First Post on Jekyll'
date: 2015-08-31 13:26:34
categories: blog development
tags: cats dogs code
custom_var: 'meow meow meow'

It doesn't matter what comes, fresh goes better in life, with Mentos fresh and full of Life! Nothing gets to you, stayin' fresh, stayin' cool, with Mentos fresh and full of life! Fresh goes better! Mentos freshness! Fresh goes better with Mentos, fresh and full of life! Mentos! The Freshmaker!

We got a right to pick a little fight, Bonanza! If anyone fights anyone of us, he's gotta fight with me! We're not a one to saddle up and run, Bonanza! Anyone of us who starts a little fuss knows he can count on me! One for four, four for one, this we guarantee. We got a right to pick a little fight, Bonanza! If anyone fights anyone of us he's gotta fight with me!

Check out all the post variables and how to retreive them in your templates here.

Looping through Posts

There's essentially two ways to loop through posts:

  • Without Pagination
  • With Pagination

Here' how to do it without pagination:

{% for post in site.posts %}

    <div class="content">
        {{ post.content }}

{% endfor %}

And here's how to do it with pagination:

{% for post in paginator.posts %}
    {% include tile.html %}
{% endfor %}


This article won't cover collections, but imagine collections as a custom content type. Not everything is a post or a page, so that's where these come in handy.

In WordPress, this would be the equivalent of a "custom post type". Or, in ExpressionEngine or other CMS's, a custom "channel".

You can read about setting them up here.

Data files


"Data files" are collections of pure, raw, and static data. Think of these as variables or groups of variables. You can have data files be in .yml, .yaml, .json, or even a .csv.

I personally prefer to put everything custom in here and not in my _config.yml file. I separate custom variables into data files because they're "watched" by Jekyll during development. Variables in _config.yml are set when the site is built - and that's it.

Some good example use cases:

  • Site navigations
  • Global variables that are site-wide
  • Misc. footer stuff
  • Google Analytics tracking code
  • Etc...

You can have as many data files as you want. Just put all of them in a folder called:


To retrieve the "data" in your layouts, it's as easy as:

{{ site.data.filename1.some_variable }}
{{ site.data.filename2.another_variable }}

Check them out here for more information.


Jekyll is pretty cool and easy to use - even if you don't like or know Ruby. Static CMS's definitely have their obvious benefits for users over database driven CMS's.

Make sure you checkout the demo and its code! It covers everything and more.

Here's some additional resources on Jekyll to wrap-up the tutorial:

Like this article? Follow @whatnicktweets on Twitter