Martin Häger
Full-stack software developer with DevOps experience. Blogging about programming, video games, music, electronics engineering, and all things DIY.

How This Site Gets Built
Published on August 17th 2019

It's been about ten years since last I ran a blog. The technological landscape has shifted a lot during those ten years, particularly in the web app space. We now have cool things like React, GraphQL, Let's Encrypt, Docker, and a mature Node.js ecosystem. Back then I was doing most of my web development in Ruby and Python. In this post, I'd like to illustrate how this site is put together.

The wonderful world of static site generation

The document you're viewing right now is served by GitHub. It's fully static content, generated at deploy time on Travis CI. New releases are created semantically and deployed automatically, roughly according to the following flow:

New code is pushed
Run tests
Test pass?
Mark as failure
Branch is master?
Mark as successful non-release
Branch contains new
commits to release?
Prepare release
Mark as successful release

Releases are created by analyzing the messages of commits added to the master branch. Messages are parsed as Conventional Commits, which are structured as follows:

<type>[optional scope]: <description>

[optional body]

[optional footer]

If the commit log contains one or more commits with a type of fix or feat, or a footer containing the phrase BREAKING CHANGE, a new release is created. The version number is bumped accordingly in a semantic fashion: BREAKING CHANGEs lead to a new major version (site redesigns), feats (new content or features) lead to a new minor version, and fixes (content updates or bug fixes) to a new minor version. scope and description are used to generate a changelog.

The beauty of GraphQL

GraphQL is an incredibly powerful query language, which can be used to fetch data from local files, web APIs, and everything in between. I'm currently using it to query Markdown documents and assets from disk, for example to generate the blog's index like this:

allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }, limit: 1000) {
	edges {
		node {
			fields {

However, it would be trivial to for instance pull photos off of Instagram into the site feed by simply dropping in a new data source and altering the query. From the above query, I generate one page per post and then one index page per five posts for pagination. In the future, I might create tag-based index pages as well. The pages themselves query deeper for the rendered Markdown and metadata.

Enjoyed this post? Got feedback? Consider following @kvadevack for the latest updates.

This post is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

© Martin Häger, 2018 - 2021.

v1.5.12 (changelog). Built with GraphQL, React and Semantic UI.