Jekyll 101 for Authors

2020-08-14 20 min

The purpose of this guide is to help those people who wants to have a personal or company website, a blog or just whatever kind of website.

No matter the approach chosen to build a website, a minimal technical knowledge is required. This means that someone must help you to build a site. You can hire someone or a friend can give you a hand. In the vast majority of cases, everyone ends up with a wordpress site. Which is good. But sometimes it is a bit overwhelming using wordpress to build a simple static website.

Wordpress processes requests using a php engine in order to build the required page. Each time a user makes a new page request, the server where wordpress is installed executes a new task to build just in time the page. While this behaviour is interesting on complex sites, it seems a bit overwhelming for the most websites and blogs around the globe.

Unlike Wordpress, Jekyll is a static site generator. What does it mean? It means, the website, is generated before its use. Once the content is built, it can be deployed without the need of any engine at all. Servers (Apache, Nginx) know how to handle these files.

Basically, what a browser needs is an HTML file with its style (CSS) and script (Javascript) counterparts. After requesting a web page, that is what a browser gets: a simple (or complex) HTML file. There’s no need for extra time processing.

This difference makes also cheaper the required resources to host and maintain a website.

Of course, both tools cannot be compared. While Jekyll is a small fast boat that makes possible creating simple websites, wordpress is such a big ship which offers much more than the building (compilation) process.

One of the drawbacks in Jekyll is that it makes the author to work very close to the technical side. Sometimes, you’ll find yourself struggling how to add a picture in some blog post. But the necessary know-how is not as hard as it may seems. In fact, it can be quite rewarding changing by yourself the look of the website.

Just like wordpress, Jekyll should be installed by someone who knows about. He/She is the responsible to let you how to run the Jekyll website in your local machine. So, leaving aside technical matters, let’s dive into Jekyll.

If you are one of those who likes to fiddle around with things, you can check how to install Jekyll in the official docs.

Jekyll Folder Structure

The first big difference with wordpress is that you’re not going to use the browser to access any of its elements. Most of the time you’re going to be using the file explorer of your OS. Before getting into the different available features, it’s worth taking a look at the structure of a Jekyll website.

├── Gemfile
├── _config.yml
├── _data
├── _drafts
├── _includes
├── _layouts
├── _posts
├── _sass

The default installation comes with a preinstalled theme. A Jekyll theme is a set of all the resources (HTML, style and script files) required to build a website. You can know more about themes here. Perhaps you can find one theme that fits for your website.

Gemfile and _config.yml are configuration files. Most probably, you’re not going to use them after being set. They are out of scope of this guide but sometimes we’ll get into them, specifically _config.yml, to set some options like the website title and description among other things.

Structure folders

_layouts folder keeps the templates used in your website. Basically it is source code that you won’t touch very much.

A layout file describes the whole structure of an specific page like a post. Even the content between posts is different, the page design is the same: a header, a title, the body content, a footer, sidebar options, etcetera.

Another layout example can be the homepage. Usually differs from the rest of the site.

The About page can have its own layout too.

The _includes folder stores reusable parts that compose a webpage. The header (with the navigation links) is a clear example. Instead of copying the same HTML markup among different layouts, the header can be included from another file called _includes/header.html. So there’s no need for repeating.

An include file may receive arguments, too. This way, some parts of the file can change according to the context where it has been used: a post page can show one description while the homepage shows another.

_sass directory keeps the stylesheets used in the website. Again, this is another folder that is good to know for what it is for, but you’re not going to fiddle with too much.

So far, we’ve seen the files related with the site’s structure. Let’s check site’s content pertinent folders . The ones you’re actually interested in.


Basically, a website is composed of pages and posts. A post is no more than another page meant to be read like an article in a magazine or journal, indeed.

A web page is an HTML file. Jekyll allows authors to write pages a format file called markdown. The markdown format permits authors focus in content without losing the structure design capability. A typical markdown file extension is .md or .markdown. E.g. This file is transformed into an HTML after the site has been built.

A web page can be stored anywhere in a Jekyll folder. Most commonly you want to keep them at the root folder. This way, files are accessible by appending the file name in the url:

Remember, the index.html is the default page shown when a url is accessed:

This server feature can be used to prettify the url. Not only works with root folders, it’s possible to create an index.html within nested folders. Carry on with the example, instead creating an about.html right in the Jekyll root, it can be generated within a folder named about containing an index.html. When reaching the about page, the url will look like

This option may be set globally or by page using the permalink variable. We’ll see in a bit.

An example of a markdown file looks like the figure shown below.

layout: default
title: About
Lorem ipsum dolor sit amet...

The file starts with three dashes in what looks like a set of options and ends with another three dashes. This is what is called the frontmatter.


If you recall the _layouts folder, where HTML templates are stored, seems reasonable to think the layout option in the frontmatter seen above is somehow related to the layouts folder. If that was your guess, you were right. In fact, it is telling to jekyll to make use the default.html layout to wrap the content in this file.

A layout file can only be one type: HTML. Therefore, there’s no need to add the file extension (.html) when setting the layout option in the frontmatter. Just the file name suffices.

Unlike the layout option, which is meant to feed Jekyll engine, the title option is not required. At least not for Jekyll. title is a site’s variable. Its value will be replaced whenever the title variable is found in any file containing the frontmatter at the beginning. A file without frontmatter will not be processed, only copied.

But, where exactly has the title variable been used? As you well guessed, it is the default.html file where the <title> html tag is declared. Usually, the <head> tag and its body resides in a specific include file (_include/head.html) to be able to be reused between templates. For shortness we work with a layout.

To grasp a better understanding, take a look at the sample of a default.html file below.

<!DOCTYPE html>
<html lang="en">
    <!--====== Required meta tags ======-->
    <meta charset="utf-8" />
    <meta name="description" content="" />
    <title>{{ page.title }}</title>
    {{ content }}

The page.title variable corresponds with the title in the frontmatter. After building the site, the page.title word is replaced by the title value in the frontmatter. The same process is done for any of the files found in the Jekyll folder. Remember, only files containing frontmatter are processed.

All frontmatter variables defined in a page are contained on the page variable provided by Jekyll. Therefore, if you add a description variable, it will be accessed using the `` expression like title.

It is important to mention to do a proper variable replacement, Jekyll variables must be wrapped between ``.

The wrapper symbols {{ and }} come from a language called liquid. Jekyll relies on liquid to offer programming capabilities in the templates. We’re not going to dive in programming techniques in this guide. That’s something a developer should do. Anyway, if you feel curious, check the official liquid docs to know more about. You can also start looking at the liquid reference in the Jekyll docs.

The {{ content }} expression is where the file using the layout will be embedded. When changing things in a layout, in case you remove the {{ content }}, do not forget to add it again. The page using the layout won’t be embedded in the next build.

frontmatter options can also be used to declare all the variables that you want. You can add a footer_txt option to be used in the website footer. Each time a page defines the footer_text, the value will be attach at the footer. Of course, the specific file (layout or include) must be modified according to the new requirement.


One of the most interesting aspects of Jekyll is its capability to store post entries without a database. Unlike Wordpress, which requires installing a database for this matter.

The way Jekyll manages posts is by storing them in the _posts folder. Each file must follow the same convention:

A post file looks like the about page example above. It must contain the frontmatter to be processed by Jekyll.

Post layouts are different from the one used by a page, so in the frontmatter section of a post file, the layout option must be changed to the expected template: usually it is named post. Therefore, the file within the _layouts folder is post.html.

layout: post
title: "My New Post"
date: 2020-08-08T00:00:00.284Z
Lorem ipsum dolor sit amet...

Because the layout is post, the corresponding file in the _layouts folder is named post.html.

Just like pages and posts, layouts may specify another layout. Thus, the post.html layout can use the default layout.

layout: default
    <h1>{{ post.title }}</h1>
  {{ content }}
      Posted on
      <time datetime="{{ }}">{{ | date: 'Y%-%m-%d'}}</time>
      by {{ }}.

Now, the post file is wrapped by the post.html, which at the same time is also wrapped by the default.html layout. Isn’t cool?

Notice the {{ content }} is present again in the post.html layout. The {{ content }} expression is required to append the content body of the file which uses the layout. In this particular case, the content body shown in the defaut.html file is what the post.html contains. And, the post.html embeds the content body of the post file which uses the layout post.


Drafts works much the same as posts. The only difference is that the files are stored in the _drafts folders.

Drafts are not shown by default. To preview the drafts while running Jekyll locally, the option --drafts must be append to the jekyll command. You can see how to do it at the end of this article.

A bit of Markdown

After having a look at pages and posts and knowing what is the frontmatter thing, it is time to see how a page can be enriched by using the Markdown format.

As the introduction of the Markdown official documentation states, “Markdown is a text-to-HTML conversion tool for web writers”. The quote is pretty self-explanatory.

But, how to actually use it? The concept is pretty simple. By using some special syntax elements in the document, the text gets wrapped in concrete HTML tags in the resulting file.

For instance, the different HTML headings can be declared as below.

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

The output file will look like this.

<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>

By defauly, any piece of text without a line break is considered a paragraph.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. 

Results in the next HTML output.

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>

The text can be emphasise by using symbols like * and _, which will be transformed to HTML. Notice, both * and _ offer the same output.

*Lorem ipsum dolor sit amet*
_Lorem ipsum dolor sit amet_

**Consectetur adipiscing elit**.
__Consectetur adipiscing elit__.

Which results in the next result.

<p><em>Lorem ipsum dolor sit amet</em>
<em>Lorem ipsum dolor sit amet</em></p>

<p><strong>Consectetur adipiscing elit</strong>.
<strong>Consectetur adipiscing elit</strong>.</p>

There are also, lists, quotes, links, images, etc. Please, refer to the offical guide to know more on the Markdown syntax. You can also test it in the online tool available in the same website. Another interesting resource is this Markdown guide.

The language is pretty simple and straightforward. You’ll get use to it in less time than you say supercalifragilisticexpialidocious.


Jekyll allows loading data from files. The supported formats are YAML, CSV and JSON. This way you can store data separated from content.

Each data file must be stored in the _data folder.

Suppose you want to import an excel file to your website but you want to be able to layout it according to the website’s styles. What you can do is exporting the excel to a CSV file and place it in the _data folder.

Here below is a CSV file, named deniro.csv, with two decades of Robert De Niro films.

1970,17,Bloody Mama
1970,73,Hi Mom!
1971,40,Born to Win
1973,98,Mean Streets
1973,88,Bang the Drum Slowly
1974,97,The Godfather Part II
1976,41,The Last Tycoon
1976,99,Taxi Driver
1977,67,New York New York
1978,93,The Deer Hunter
1980,97,Raging Bull
1981,75,True Confessions
1983,90,The King of Comedy
1984,89,Once Upon a Time in America
1984,60,Falling in Love
1986,65,The Mission
1987,100,Dear America: Letters Home From Vietnam
1987,80,The Untouchables
1987,78,Angel Heart
1988,96,Midnight Run
1989,47,We're No Angels

Now you can access to the data file through the global variable as shown below.

// _includes/deniro.html
  {% for film in %}
    <li>{{ film.title }} ({{ film.year }})</li>
  {% endfor %}

In the sake of reusability, an include file has been created, so the Robert De Niro films can be included in any layout, page or post.

Each time you want to update the data file, you just export again the excel to a CSV and replace the one in the _data folder. New time the website is built, the new data will be available from the include file wherever has been used.


Defining a collection is like declaring a new type of resource. Not for nothing, both posts and drafts are a kind of collection. The difference between a post and a custom collection is that posts are time based.

Collections are defined in the _config.yml file.

Assume you like to review the books you’ve read. But you don’t want to treat them as blog entries. Instead, a new collection can be created only for books.

  - books

After definition, create a folder with the same collection name with an underscore at the beginning, _books.

From now on, each file in folder corresponds with a book. Let’s create the file _books/

title: Cien años de soledad
author: Gabriel García Márquez
year: 1967
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat.

Like any other file in Jekyll, it starts with a frontmatter section to make the file be processed. The frontmatter can be used to add additional information in addition of the content. And because it is a markdown file, you can use all the benefits this language offers.

By default, collections are not rendered like posts. In order to generate the HTML counterparts, the collection configuration must be updated setting the option output to true.

    output: true

Just like any file you can specify a layout for books.

All books are stored in the books folder of the website directory, matching the collection name. This can be changed by updating the permalink option in the collection configuration.

    output: true
    permalink: /:collection/:name

Note the : after each slash symbol. That’s a placeholder. It means, that token will be replaced by the collection name (books) and the file name (cien-anos-de-soledad). There are other placeholders you can use.

Setting options globally

Until now, all the options have been set in the frontmatter section of each file. It can be quite repetitive and boring having to declare always the same things. Jekyll allows establishing some of the options globally.

As you remember, each post contains the layout attribute set with value post. Most of the time, not to say always, posts have the same layout. So, why not to place that option in the _config.yml file.

      path: ""
      type: "posts"
      layout: "post"

By declaring the default scope for posts each post, files stored in the _posts folder, inherits the layout layout set to post.

The same approach can be taken for pages by just changing the scope to pages.

      path: ""
      type: "posts"
      layout: "post"
      path: ""
      type: "pages"
      layout: "default"

The scope type can be one of the next values: pages, posts, drafts or any collection type. Notice, an empty scope will apply to every file.

The path property allows to enforce the preferences scope only to a specific folder in Jekyll.

      path: "meetings"
      type: "pages"
      layout: "meeting"

In the example above, page files stored in the meetings folder will make use the meeting.html template.

One last important thing to mention is the settings precedence . All frontmatter values takes precedence over global variables defined in _config.yml. Therefore, the layout option in a post or page file, overrides the globally set layout in _config.yml.


There are three types of namespaces available in Jekyll. A namespace is a container which groups a set of variables declared in the same scope. Don’t be overwhelmed by the description, it is easier than is seems. The three scopes, or namespaces, are site, layout and page.

Settings defined in _config.yml are available through the global variable site. E.g. the website title is declared in the _config.yml, so to get that value you’ll write {{ site.title } anywhere in the website.

layout: default
Welcome to {{ site.title }!

Variables defined in any layout frontmatter correspond to the layout scope. They are available through the global variable site.layout

layout: default
Welcome to {{ site.layout.title }!

And finally, variables defined in the page frontmatter are accessed through the global variable Remember, a post is also a page, so the same variables declared in a post are accessed from

layout: default
Welcome to {{ }!

Jekyll provides plenty of variables but you can also add your custom variables in all scopes. These variables will be available under the specific scope they were defined.


Before ending this 101, it is important to be able to check how changes looks like. To do so, you need to get access to the terminal. It is not scary as it seems but if you’re not use to it can be a bit frustrating.

One way to ease it up the process to open a terminal, it is opening directly from the current window directory. I think the Windows OS has this option available by default. In order to do the same in Mac OS you can check how in this post.

Once the terminal is open at the right path (the Jekyll folder) you can run the next command to start the server.

$ bundle exec jekyll serve

You’ll should see the next output.

Configuration file: /Users/john/yourwebsite/_config.yml
            Source: /Users/john/yourwebsite
       Destination: /Users/john/yourwebsite/_site
 Incremental build: disabled. Enable with --incremental
       Jekyll Feed: Generating feed for posts
                    done in 0.21 seconds.
 Auto-regeneration: enabled for '/Users/john/yourwebsite'
    Server address:

The last line tells which is the url address you must type in the browser. By default is

To see the drafts, you’ll use the same command but setting the --drafts option.

$ bundle exec jekyll serve --drafts

If what you want is to just build the website, the command to run is the one below.

$ bundle exec jekyll build
# or 
$ JEKYLL_ENV=production bundle exec jekyll build

The last command will do the same as the previous but optimizing the website. Anyway, don’t get too stressed by the building matter. This is a task that commonly a developer should do.