Make a Static Website with Jekyll

Make a Static Website with Jekyll

A tutorial on how to install Jekyll (the static site generator) and create a simple theme for blog posts and regular pages. Written on a macOS environment.

Jekyll is a static site generator that runs on the Ruby programming language. You may have heard of Jekyll or static site generators, but don’t know how or where to get started. This guide is intended to be a complete tutorial, and require no additional resources to get you up and running with Jekyll.

While Jekyll is advertised as a blogging platform, it can be used for static websites as well, much like WordPress. Jekyll harnesses the power of markdown, which makes writing HTML much easier and more efficient. Additionally, Jekyll has Sass built in, and if you’ve never used a CSS preprocessor, it’s a great time to learn. If you already know how to use Sass, you’ll feel right at home.

This is what the website we make will look like:

View Demo View on GitHub


If you don’t have a basic knowledge of command lines and Git, please read the getting started with Git article. This will cover everything you need to know to get started with using Git and the command line.


  • Learn what a static site generator is
  • Install Jekyll
  • Create a custom website running on Jekyll and Sass
  • Deploy a Jekyll site to GitHub pages

Additionally, this tutorial is currently Mac only. If I get a request to do a Windows tutorial, I’ll look into it, but until then, you must be running OSX for this tutorial to be effective.

What is a static site generator?

A static site generator builds a website using plain HTML files. When a user visits a website created by a static site generator, it is loaded no differently than if you had created a website with plain HTML. By contrast, a dynamic site running on a server side language, such as PHP, must be built every time a user visits the site.

You can treat a static site generator as a very simple sort of CMS (content management system). Instead of having to include your entire header and footer on every page, for example, you can create a header.html and footer.html and load them into each page. Instead of having to write in HTML, you can write in Markdown, which is much faster and more efficient.

Here are some of the main advantages of static site generators over dynamic sites:

  • Speed – your website will perform much faster, as the server does not need to parse any content. It only needs to read plain HTML.
  • Security – your website will be much less vulnerable to attacks, since there is nothing that can be exploited server side.
  • Simplicity – there are no databases or programming languages to deal with. A simple knowledge of HTML and CSS is enough.
  • Flexibility – you know exactly how your site works, as you made it from scratch.

Of course, dynamic sites have their advantages as well. The addition of an admin panel makes for ease of updating, especially for those who are not tech-savvy. Generally, a static site generator would not be the best idea for making a CMS for a client. Static site generators also don’t have the possibility of updating with real time content. It’s important to understand how both work to know what would work best for your particular project.

Installing Jekyll

We’re going to install Jekyll locally before deploying anything to GitHub pages.

Install Command Line Tools

Open Terminal. Check to see if you have XCode Command Line Tools installed by typing gcc -v. At this point, it will prompt you to install if you don’t. Or run this code to install:

xcode-select --install

Install Ruby

Ruby should come pre-installed on all OSX computers. You can check if Ruby is installed by running ruby -v. It should return with Ruby version 2.0.0 or higher.

ruby 2.0.0p645 (2015-04-13 revision 50299) [universal.x86_64-darwin15]

If for some reason you’re running a lower version, you can update.

sudo gem install ruby

If you plan on using Ruby for more purposes, it might be advisable to install Ruby Version Manager. Otherwise, the above commands are perfectly fine.

Install Bundler

Bundler is a package manager that will aid you in installing all the Jekyll dependencies.

sudo gem install bundler
Successfully installed bundler-1.10.6
Parsing documentation for bundler-1.10.6
1 gem installed

Create Gemfile

Create a directory, and add a file called Gemfile. The file doesn’t contain an extension. Type the following contents into the file and save it.

gem 'github-pages'
source ''

In Terminal, run this command in the directory that contains the Gemfile:

bundle install

This command should run for a while. It might ask you for your sudo password, or for you to run sudo bundle install. When it’s finished, it will say something like this:

Bundle complete! 1 Gemfile dependency, 55 gems now installed.

Install Jekyll

Great! Now that that’s finished, you can successfully install Jekyll. I’m going to call my project startjekyll

jekyll new startjekyll
New jekyll site installed in /Users/tania/Sites/startjekyll.

Move to the new directory.

cd startjekyll

And initialize a new Git repository.

git init
Initialized empty Git repository in /Users/tania/Sites/startjekyll/.git/

At this point, all the setup is complete. In your project directory, run the following code:

jekyll serve

This command runs a “watch” on the entire server. Changes made to any files (except the configuration file!) will be compiled into static HTML.

Now go to the url http://localhost:4000. You will see this page.

Congratulations, you’ve just installed Jekyll! If you type CTRL + C in Terminal, it will end the running process and the site will no longer be served to localhost. Simply run jekyll serve again and it will come back up.

Creating a Jekyll theme

With Jekyll, we’ll be able to process SCSS (Sass) files into CSS (.scss -> .css), and Markdown into HTML (.md -> .html). No additional task runners or Terminal commands are required!

There are a few important things to know about the Jekyll file system.

  • The “distribution” folder is called _site. This is what the static site generator generates! Never place any files in that folder; they will be deleted and overwritten.
  • The _sass folder is for Sass partials. Every file in here should begin with an underscore, and it will compile into the css folder.
  • Any file or folder placed into the main directory will compile into the _site directory as-is.

There is more to know, but we’ll learn along the way.

I’m going to go through all the files from here on out. If you’d rather clone the Git repository, you can view it here. All the files in the repo will be the same as what I display here.


In the main directory, there’s a file called _config.yml. It looks like this:

# Site settings
title: Your awesome title
description: > # this means to ignore newlines until "baseurl:"
  Write an awesome description for your new site here. You can edit this
  line in _config.yml. It will appear in your document head meta (for
  Google search results) and in your feed.xml site description.
baseurl: "" # the subpath of your site, e.g. /blog/
url: "" # the base hostname & protocol for your site
twitter_username: jekyllrb
github_username:  jekyll

# Build settings
markdown: kramdown

Pretty obvious. There are two important things to know about the config file:

  • Changes made to _config.yml will not be watched by jekyll serve. You must restart and reserve Jekyll after any config changes.
  • All indentation is mandatory and must be made with two spaces, or else the file will not work.

I’m going to make a few changes to the configuration.

# Site Settings
title: Start Jekyll
description: >
  A guide to getting started with Jekyll.
baseurl: ""
url: "http://localhost:4000"
twitter_username: taniarascia
github_username:  taniarascia
# Build Settings
  sass_dir: _sass
include: ['_pages']
  input: GFM

I changed the base URL to http://localhost:4000. This will be for the dev configuration. I’m declaring _sass as the sass directory, to ensure the Sass compiles correctly. I’m adding include: ['_pages'] so that custom pages will be organized into their own directory, and input: GFM will allow Github Flavored Markdown.

Customizing your Jekyll Theme

The default styles try to be basic, but they’re still far too stylized for my liking. We’re going to override all the styles and make them much more simple. You can turn off the Jekyll serve at this point and just start saving files. We’ll go from top to bottom alphabetically.

I’m using my own name as an example, but obviously change everything to match you.


In Jekyll, _includes are files that should show up on every page – header, footer, etc.

	<p>By <a href="">Tania</p>

Any head metadata.

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</title>

	<link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}">
	<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}">
	<link href=',300,700,800,600' rel='stylesheet' type='text/css'>
	<link href=',300' rel='stylesheet' type='text/css'>


Your navigation and header. I will dynamically load all pages into the navigation bar, except for the blog page, which I will load manually.

	<div class="container">
				{% for page in site.pages %} {% if page.title %}
				<li><a href="{{ page.url | prepend: site.baseurl }}">{{ page.title }}</a></li>
				{% endif %} {% endfor %}
				<li><a href="{{ "/blog" | prepend: site.baseurl }}">Blog</a></li>

	<h1><a href="{{ site.baseurl }}">{{ site.title }}</a></h1>


The layout that your content will conform to.

<!DOCTYPE html>
{% include head.html %}

	{% include header.html %}
			{{ content }}
		{% include footer.html %}

layout: default

<h2>{{ page.title }}</h2>
    {{ content }}

All the dashes at the top are mandatory. If you don’t include them, the website won’t work properly. For pages and posts, the default layout gets loaded, plus any additional layout information you desire.


Same as the page, but with date and author metadata.

layout: default

<h2>{{ page.title }}</h2>
<time>{{ | date: "%b %-d, %Y" }}{% if %} • {{ }}{% endif %}{% if page.meta %} • {{ page.meta }}{% endif %}</time>

{{ content }}


The default Jekyll website does not come with a _pages directory, but I like to include it so the main directory stays clean.

Now we’re creating the markdown files. Prepending them with a number ensures that they appear in the order you specify.

layout: page
title: About
permalink: /about/

About content goes here.

* A list item
* Another list item
layout: page
title: Contact
permalink: /contact/

Contact content goes here.

My e-mail is [](


I’m going to leave the post exactly as it is.

Delete from the main directory, since we’ve put it in the _pages directory.


index.html in the main directory will be the main page of the site.

layout: default

  <h2>Main Page</h2>

  Main content goes here. 


Create a new directory called blog. Inside, create an index.html. This will be the main blog page that will contain all your posts.

layout: default

{% for post in site.posts %}
		<time>{{ | date: "%b %-d, %Y" }}</time>
		<h3><a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a></h3>
{% endfor %}

<p>subscribe <a href="{{ "/feed.xml" | prepend: site.baseurl }}">via RSS</a></p>


The css directory in the root should contain one file – main.scss. Edit it to contain the following:

# Front matter comment to ensure Jekyll properly reads file.

Leave the top part exactly as is.


The absolute last directory that we need to edit – the sass partials. Create each of these files in the _sass directory.


Variables, mixins, and resets will go here.

$content-width: 800px;
$main: #19CCAA;
$font-style: 'Open Sans', sans-serif;
$font-color: #262626;
$link-color: #425469;
$link-hover-color: $main;
$heading-font: 'Muli', sans-serif;
$heading-font-color: #425469;
$light: #E7EDF4;
$header:  #1D1425;

*::after {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

Simply remove this line from the file:

    @extend %vertical-rhythm;

All my styles will go in here. I made a simple, responsive website that doesn’t rely on any frameworks.

body {
	margin: 0;
	color: $font-color;
	font-family: $font-style;
	font-size: 1.1em;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
h3 {
	font-weight: 600;
	color: $heading-font-color;
	font-family: $heading-font;
	line-height: 1.5;
h1 {
	color: $main;
	font-size: 2.5em;
	a:visited {
		text-decoration: none;
		color: $main;
h2 {
	font-size: 2em;
a:visited {
	color: $link-color;
	text-decoration: underline;
	font-weight: bold;
a:hover {
	color: $link-hover-color;
	text-decoration: underline;
header {
	background: $header;
	padding: 0px 15px;
	text-align: center;
	margin: 50px 0 0;
	height: 50vh;
	display: flex;
	justify-content: center;
	align-items: center;
main {
	padding: 0 15px;
	max-width: $content-width;
	margin: 0 auto;
time {
	color: #898989;
.container {
	max-width: $content-width;
	margin: 0 auto;

/* Aside */

aside {
	position: fixed;
	top: 0;
	left: 0;
	background: #fff;
	width: 100%;
	z-index: 2;
	border-bottom: 1px solid lighten($light, 30%);
	box-shadow: 0px 1px 1px RGBA(4, 25, 54, .1);
	nav {
		float: left;
		max-width: 800px;
		margin: 0 auto;
		ul {
			margin: 0;
			padding: 0;
			list-style: none;
			li {
				float: left;
				position: relative;
				a {
					text-decoration: none;
					display: block;
					padding: 15px;
					font-family: 'Muli', sans-serif;
					line-height: 20px;
					margin-bottom: -1px;
					box-shadow: 0;
					&:active {
						background: $header;
						text-decoration: none;
						color: $main;
		&:after {
			content: '';
			display: table;
			clear: both;
footer {
	text-align: center;
	padding: 40px;

Serve Jekyll

At this point, all the files are ready and jekyll can be served.

jekyll serve

If you inserted all the code exactly as above, the sass partials will compile into the main.scss. All the rest of the files will write to _site site, which is the distribution folder.

Server running… press ctrl-c to stop.

If I make a change to any of the sass files, they should compile.

Regenerating: 1 file(s) changed at 2015-11-30 02:54:11 …done in 0.090263 seconds.
Regenerating: 1 file(s) changed at 2015-11-30 02:54:11 …done in 0.120487 seconds.

Pushing Jekyll site to GitHub pages

Create an empty repository in GitHub. Mine is startjekyll, so the Git repo URL is this:

There is one change that needs to be made in order to have one site for both your local Jekyll and the live GitHub pages.

Duplicate your _config.yml and call it _config_dev.yml.

Leave the _config_dev.yml as is, and change _config.yml for the live site.

baseurl: "/startjekyll"
url: ""

Now, when you want to work on the site locally, you will run the following command:

jekyll serve --config _config.yml,_config_dev.yml

And it will load the information from the dev config.

Serve your Jekyll one last time to ensure all the final changes have been updated. Here are the commands to push the site to GitHub pages:

git remote add origin

Add the GitHub repository.

git checkout -b gh-pages

Ensures that you’re on the gh-pages branch, not master.

git add .

Track all files.

git commit -am "Initial commit"

Commit all files.

git push origin gh-pages

Push all files to gh-pages branch.

At this point, you should be able to open up, and it should be your Jekyll project! Without using any external task runners (like Grunt or Gulp), you can now work on the Sass files on your website, and serve up markdown files in place of HTML.

From here, it will be very easy to customize Jekyll to your liking. I purposefully kept every page as simple as possible, using semantic HTML5 tags. I sincerely hope this guide helped get you up and running with Jekyll. I documented all the steps along the way to ensure that the Sass will compile properly, and you won’t have issues being on the right branch to push to GitHub pages.

If you came across any trouble or confusion, please let me know and I’ll improve the tutorial.

Share to Twitter

Write a response

Your email address will not be published.

62 responses

  • Muhammad Ghazanfar Ali says:

    1. A little confusion at “_syntax-highlighting.scss
    Simply remove this line from the file:

    @extend %vertical-rhythm;”
    You actually did not mention to create a file in _sass directory and then deleting the line. I remained stranded here for a while.
    2. I had already run the 3 commands given on so 1 third of the tutorial, being a beginner, was a bit confusing for me thinking if I still need to install the stuff or not.
    The rest of the tutorial worked like anything for me. Thank you so much!

    • Tania says:

      Hi Muhammad,

      For the first part, each section is laid out by directory and the files that should be created within. However, I added a line to try to make this more obvious. For the second part, unfortunately I can’t know if someone has already attempted to install Jekyll in the past, so I simply have the full instructions for installation.

  • Kirk says:

    Hey Tania, thanks for all of your great blogs!

    I’m wondering if it is possible to create a Terminal command that runs all of these steps to create a barebones setup in a current working directory for Jekyll with a Gulp configuration? Any advice on where I can learn more about how to set this kind of thing up to avoid running through all these steps for each project?

    I thought these were called “development environments” but the Google results say otherwise.

  • Excellent tutorial! Thank you so much for writing it. Going through the process right now.

  • Grant Smith says:


    Really nice write up. So I am new to Jekyll so this maybe something a little obvious? Jekyll 3.3.1 now installs a theme called Minima by default. I’m struggling to work out how to install Jekyll, all the dependancies but not the theme.

    Alternatively what is safe to just bin?

    Many thanks

    • Tania says:

      Just bin everything except _config.yml and _config_dev.yml and go through my above tutorial, then once you have a super-basic site set up, design it as you like.

  • Abubakar says:

    hi Tania i love your tutorial and it has help me a lot and will not hesitate to subscribe to your blog thanks a million times

  • Marcelo says:

    Very cool! thanks a lot

    how do you add comments?

  • jayground says:

    Thanks for nice tutorial material first.

    Well, I am just beginner of Jekyll and HTML syntax.
    When I found usage of ‘main’ syntax, it said that “It should not contain any content that is repeated across documents.”
    In your code here, you put footer.html inside main tag.
    I wonder if you did it intentionally or I misunderstood how to use main tag.

  • René Tigerstedt says:

    Thank you Tania for the excellent Jekyll tutorial! The best one that I have come across!

  • GB says:

    Thanks for the write up!


    Hi Tania,

    When you say:

    “The css directory in the root should contain one file – main.scss. Edit it to contain the following:

    # Front matter comment to ensure Jekyll properly reads file.


    Do you mean that this code should be added to the CSS or should it replace the CSS? And should it only replace the top part of the CSS or should it replace all the code in that file? Let me know. Thanks, Andy

  • Griffin says:

    Thanks – this is the best getting started guide I have found

  • Yaya says:

    Thanks for this nice article.
    I’m having some errors when running “jekyll serve” :

    ” Conversion error: Jekyll::Converters::Scss encountered an error while converting ‘css/main.scss’:
    Extend directives may only be used within rules. on line 1″

    Do you have any ides ?
    May I know which version of nodejs are you using ?

  • Kevin Liu says:

    This is a really awesome guide for starters. Thank you very much for making it!

  • jeanpokou says:

    best article out there for jekyll, thanks

  • Bishal says:

    Great post! Thank you for this. I was able to get my Jekyll site up in a few hours.

  • RL says:

    Thanks for the tutorial. Quick question:

    My site looks fine on local when moved into Git it looks like all the styling is gone. The pages are displaying plain white with text. Any idea why?

  • Greg says:

    Really great tutorial!

    Quick note on something I spent a while trying to figure out. If you’re deploying your Jekyll site to Heroku (using a method like this:, the current version of Jekyll (3.2.1 as of this writing) doesn’t load the blog posts correctly. If you downgrade to Jekyll version 3.1.6, it’ll work beautifully.


  • Andrew Epstein says:

    Perhaps this a stupid question, but I am trying to follow your instructions and when I try to create a Gemfile
    in the directory outside of where I want the Jekyll directory to live, I get this message on Terminal:

    ANDREWs-iMac:portfolio andrewepstein$ touch gemfile
    ANDREWs-iMac:portfolio andrewepstein$ ls
    Gemfile _config.yml _posts css feed.xml index.html
    ANDREWs-iMac:portfolio andrewepstein$ gem ‘github-pages’
    ERROR: While executing gem … (Gem::CommandLineError)
    Unknown command github-pages
    ANDREWs-iMac:portfolio andrewepstein$

    I’m very new to this but any help/guidance you could offer would be greatly appreciated. Thanks, Andy

    • Greg says:

      Hey Andrew –
      First off, the Gemfile must be capitalized. You can fix that by running

      mv gemfile Gemfile

      Next, to install a gem, you need to use the ‘install’ command, like so:

      gem install github-pages

  • anon says:

    Dear Tania,

    Thanks for a thorough walkthrough of the basics of Jekyll on git. Really helps newcomers with a plug-and-play style approach to making a flexible website without much knowledge of scss or even basic html.

    I think that most people who are going to use this might enjoy if they could replace the header image (now a big dark blue thing) with a customised image. Also, you haven’t covered the basics of having a _image folder, or adding images to posts, teaser images and such.

    I for one would like to replace the header image with one of my own. And it would be fantastic, if the hovering over links such as “About” “Blog” etc. included that same image. Is that possible at all?

    very best,

  • rts says:

    Hey Tania,

    Wondering if the link

    <link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}">

    should have /css/main.css? This is causing me an error because /css/main.css does not exist. Only main.scss exists.

  • Matt says:

    Great tutorial, I’ve been banging my head on the table trying to get anything other than the basic site to run.

    I hit a few snags, but overall every helpful. Would be great to see a tutorial on how to add something like Materialize into Jekyll.

  • kmkrn says:

    Thank you for sharing such a clear tutorial! I am using it to finally move from WordPress to Jekyll. However, I have a little problem with a link in footer: By Tania I’ve changed this reference’s address to mi Github page. However, it redirects me to some really monstrous address when clicked from the main page: If I click on it from the blog post’s page, it becomes even more ridiculous: What could have been done wrong?

  • red raccoon says:

    I have created it, but how do I add new blog posts?

  • Aan says:

    Thanks for great article and explanation. I’ve published an article in my blog and your blog is my reference 🙂 But only in Indonesian languages

  • AJ Solimine says:

    Hey Tania, great article!

    If any users are having trouble installing Ruby and configuring Jekyll, they can use the pre-configured Jekyll template on Nitrous ( Nitrous also has a free Jekyll publishing and hosting service called PubStorm ( that has free custom domains, rollbacks and more.

  • Arman says:

    Thank you, this was very helpful!! 🙂

  • Great article. Thanks a lot!

  • Very helpful article, Indeed 🙂

  • Ravi says:

    This guide is great! Just easy enough for me to understand everything. Thank you.

    Btw, is this site running Jekyll? If so, what are you using for comments?

  • Vikrant Negi says:

    Looking for a windows version of the above post.
    Great article by the way. I’m trying it on Windows and hope it works out fine. 🙂

  • A windows version would be very appreciated.

    Your blog is a gold mine for me.

  • João Vilaça says:

    Finally a good tutorial, this is the best one for jekyll i’ve seen in a long time, thanks a lot!

  • Tom Swan says:

    Really great tutorial, and just as I was trying to strip a Jekyll site bare so I could learn more about its workings. So thanks for the tips! Q: In your header.html include, I changed the def to the following — else there seems no way to get back to the site’s “home” page:

    <h1><a href="{{ site.url }}/">{{ site.title }}</a></h1>

    Does that make sense? Thanks again!

    • Tania says:

      Hmm, that’s odd. {{ site.baseurl }} worked perfectly fine for me. I’ll have to look into it a bit more thoroughly. Glad you liked the tutorial!

      • frank says:

        Hi Tania

        nice tutorial – thanks for sharing.
        Just two things to clarify:

        1. header.html indeed requires the following, other than stated in your tutorial above.
        {{ site.title }}
        If you navigate to any other page then “home” you will realize that pageURL refers to the URL of the current page and can´t bring you home.
        2. I am new to Jekyll (thanks to you) and wonder if a cname record can be used for this setup. Or if this setup is related to project pages as it seems you are using subdirectories.
        3. Could you imagine extending this already very realistic tutorial by one more real world requirement? Adding a guide how to organize, manage and handle real globalization by adding guidance on how to translate pages, blogs, putting nav in _data, … would be awesome. I would even donate or pay for it. Or can you be hired for a 1:1 coaching session?

  • Joseph Joy says:

    Thanks for your nice writeup. No need to publish this msg – just reporting small typo in first para: “and require to additional resources”.

  • Tamara Temple says:

    Thanks for writing this article, Tania. You lay out the process very cleanly and readably for people new to jekyll. Well-done indeed.

  • krv says:

    Nice guide Tania .. I found it on reddit and used parts of it to get my spanking new blog off the ground. Could you perhaps put instructions on how to integrate this with a custom domain (if you are using github)? Thanks!

Write a response