Blog Engineering SSGs Part 2: What are modern static site generators
Published on: June 10, 2016
11 min read

SSGs Part 2: What are modern static site generators

This is Part 2: Modern Static Site Generators, where we provide you with an overview on the subject.


What are Static Site Generators? What are they for? Why should I use them? Do they have limitations? How can I use them with GitLab Pages?

If these questions ring a bell, this series of posts is for you! We are preparing three articles around the same theme "Static Site Generators (SSGs)".

This is Part 2: Modern Static Site Generators, where we provide you with an overview on the subject.

The previous post was Part 1: Dynamic x Static Websites, where we briefly explained the differences between them, and their pros and cons.

Stay tuned for the next post: Part 3: Build any SSG site with GitLab Pages!

Note: For this series, we assume you are familiar with web development, curious about Static Site Generators, and excited to see your site getting deployed with GitLab Pages.

What's in this overview?

  • TOC

Benefits of Modern Static Site Generators

Static Site Generators (SSGs) are software created to automate web development to output static sites from dynamic writing. So, we code dynamically and publish statically. No pain, all gain.

The most fascinating thing of any SSG is the ability to code fast, save money (on web hosting), and incredibly decrease the page loading time (compared to server-side dynamic webpages). Also, if we have a lot of visitors at the same time, our static sites have less chance to crash due to server overload than dynamic ones.

Note: if you want to know more about it, read the introductory article for this series: "SSGs Part 1: Static x Dynamic Websites".

Structure of SSGs

The structure of SSGs is a combination of features to make static sites development faster and less repetitive. Let's take a quick look at the list below, then describe them one by one.

  • Environment
  • Template engine
  • Markup language
  • Preprocessors
  • Directory structure


The environment, also called platform, consists essentially on the programming language the SSG was written in. It will make difference on the configuration, customization, and performance of the SSG. Examples: Ruby, Python, Node JS.

Template engine

The template engine is very important we understand, since all the dynamic structure of our sites will depend on that. It's essential that we choose an SSG with a templating system that we can use comfortably. Examples: Liquid, Haml and Slim (Ruby), Twig (PHP), [Swig] (JavaScript).

To give you a picture, let's see an example for an HTML file, in which we are using the Liquid Templating Engine:

<!DOCTYPE html>
<html lang="en">
	{% include head.html %}
	{% include header.html %}
	<main class="content">
		{{ content }}
	{% include footer.html %}

As you may have guessed, we have three files for the content that repeats sitewide (head, header and footer), which are included to every page using this template. The only thing that is different is the {{ content }} of that page, which is written in a separate file, and also included dynamically to the template with this tag. Finally, all the files will be compiled to regular HTML pages before being stored in the web server. This process is called build. GitLab Pages builds any SSG.

Advantages over flat HTML

  • Minimize typography errors ("typos"): all files are considerably reduced, improving readability
  • Avoid repetition: every block repeated sitewide would be included to every page, equivalently
  • Update faster: if we change something in the file footer.html, it will affect the entire site

Markup language

Markup language is a system to write documents making them somehow syntactically distinguishable from text. Lightweight markup languages have a simplified and unobtrusive syntax, designed to be easily written within any text editor. That's what we'll use to write our content.

The majority of SSGs use markdown engines for this purpose. But there are many more lightweight markup languages used likely, such as AsciiDoc, Textile and ReStructuredText.

Among those SSGs which use markdown markup, generally we are allowed to choose which markdown engine we want to use. It is set up on the site configuration. For example, in Ruby there are a handful of Markdown implementations: Kramdown, RDiscount, Redcarpet, RedCloth.

A blog post or a page written in markdown will most likely start with a front matter section containing information about that page or post, and then comes the content just below it. This is an file used in a Jekyll site, and also an file for a Middleman site:

# front matter (between three-dashes block)
title: "Hello World" # post or page title
date: YYYY-MM-DD HH:MM:SS # date and time, e.g. "2016-04-30 11:00:00"
author: "Foo Bar" # a common variable to exemplify

# An h1 heading

Some text.

The front matter variables, which are title, date and author for our example above, can be called with template tags all over the site. With Liquid, if we write:

<h2>Title: {{ page.title }}</h2>
<p>Date: {{ }}</p>	 
<p>By {{ }}</p>

The output would be:

<h2>Title: Hello World</h2>
<p>Date: 2016-04-30 11:00:00</p>
<p>By Foo Bar</p>

The content for our example would output simply:

<h1>An h1 heading</h1>
<p>Some text.</p>


The preprocessors are made to speed up our development process too. They simplify the way we code, and then compile their own files into standard ones. Examples: Sass and Stylus for CSS, CoffeeScript for JavaScript.

Again, just to give you a picture, check a CSS code block written in CSS directly, and the other written in Sass:


h1 {
  color: #333;
  padding-top: 30px;
p {
  color: #333;


$clr = #333
  color: $clr
  padding-top: 30px
  color: $clr

In a large-scale styling, saving all curly brackets { } and semi-colons ; makes a lot of difference for who is typing. Also, with Sass variables (e.g., $clr above), we can define some standards and apply them all over our stylesheets. In the end, everything will be compiled to regular CSS. There are more interesting features and advantages of preprocessors, but that's not in focus on this post.

By the way, the given Sass example will be compiled exactly to the CSS code above it.

Directory structure

The directory structure is different for each SSG. It's important to study the file tree before we start working with an SSG, otherwise we might face odd build errors that we won't understand solely because we didn't use its structure accordingly. Examples: Hexo structure, Middleman structure, Jekyll structure. So, just make sure you add new files to the correct directories.

SSGs built-in features

In addition to their standard components, there are also a number of built-in features that make building and previewing static sites easier - and faster. For example:

  • Most of SSGs have a pre-installed server for previewing the sites locally
  • Some of them also contain in their installation package a LiveReload plugin, so we don't need to refresh the page in our browser every time we save it
  • Most of them provide us with built-in compilers for their supported preprocessors

Blog-Aware SSGs

One of the most attractive features for the majority of modern SSGs is the ability to manage blog content without the need of storing posts, or post contents, in databases or in server-side-only processed files.

A blog-aware website generator will create blog-style content, such as lists of content in reverse chronological order, archive lists, and other common blog-style features. How would an SSG do that?

With their file tree and their template engine. The file tree defines the specific directory for posts and the template engine calls the posts dynamically.

With a for loop through the posts, they can be displayed in a single page, as illustrated below (with Liquid):

    {% for post in site.posts %}
        <span>{{ }}</span>
          <a class="post-link" href="{{ post.url }}">{{ post.title }}</a>
    {% endfor %}

This code means that, for each post within the site posts ({% for post in site.posts %}), all of them would be displayed as items of an unordered list of posts, within links for their respective paths.

Of course, we can adapt the HTML structure according to our needs. Also, we can use the blog-aware structure to create different kinds of dynamic insertion. For example, we could use them to display multiple things within the same category, as a collection of photos, books, etc. So, each time we add a new item, the SSG uses it's template engine to bring our collections together.

Supported content

Static servers fully support any language or script interpreted by browsers, known as client-side processing. Let's just remember that a static site is essentially composed of three components: the structure (HTML), the layout and styles (CSS), and the behavior (JavaScript).

Supported languages and file extensions

  • Common file extensions: .html / .css / .js / .xml / .pdf / .txt
  • Common media files: images, audio, video, SVG

Supported interactive services (examples)

Supported utilities (examples)

Limitations of SSGs

We've just described what we can do with SSGs. Now let's see what we cannot.

  • Register users
  • Have admin access
  • Send emails via mail() function
  • Use any server-side language or script

These kinds of actions depend necessarily on server-side processing, which are not handled by static-only web servers, as we explained in the first post of this series.

Overcoming the limitations

User Authentication

Despite not having the ability to register users, nor having admin access for ourselves, with tools like Firebase we can power-up our static site with user authentication. Find more cool stuff here, from the same source.

Content management

We can edit the content of our SSGs directly from the web browser with We can't create new pages, but we can edit pages' content easily. Follow the tutorial to learn how to implement this for your own website.

Contact Forms

Yes, we can offer contact forms in our static websites. We can't process the server-side script in our static-server, but there are some third-party services we can use for that. For example, you can try Formspree, FormKeep, Wufoo, FoxyForm, Google Forms or any other related service . However, if you want to take control over your mail script, you can try the parse method with SendGrid.

JavaScript disabled

Everything based on JavaScript is allowed to be added to our static sites. However, if JavaScript is disabled on the user's browser, those scripts will not work. But there is something we can do to minimize this issue. We can add a <noscript> tag to our web pages, containing a message that will be displayed only if JavaScript disabled:

<noscript>Please enable JavaScript on your browser for a better experience with this website!</noscript>


Hopefully now you understand the logic of Static Site Generators, how we can use them wisely, and what we can and cannot do with them. Dynamic websites are great, for sure. But if we don't need all their functionality, SSGs are certainly wonderful alternatives.

In the third post, which is the last chapter of this series, we will bring you a lot of examples for SSGs already running on GitLab Pages. Therefore, we're confident you'll be able to see and understand different GitLab CI configurations, and create your own.

We already have prepared a bunch of SSGs example projects, you'll find them in the GitLab Pages official group. You are very welcome to contribute with new SSGs.

Don't you have an account on yet? Let's create one! Remember, we can use GitLab Pages to build any SSG for us and host it for free!

Follow @GitLab on Twitter and stay tuned for updates!

We want to hear from you

Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum. Share your feedback

Ready to get started?

See what your team could do with a unified DevSecOps Platform.

Get free trial

New to GitLab and not sure where to start?

Get started guide

Learn about what GitLab can do for your team

Talk to an expert