How to build a blog with Gatsby

19 hours ago | October 17, 2020 | 30 minute read

In my previous blog post I talked about finding the motivation to finally go away and start a blog. If you’ve been similarly inspired you might now be thinking about how you’re actually going to do that.

If you watched the conference talk I linked to in my previous post, you’ll know that Troy Hunt mentions Ghost as a great platform you can use to start blogging with no upfront setup required. This looks like a really good option If you’re itching to get started right away, and aren’t fussed about having complete and total control.

I thought about using Ghost, but instead decided it would be a good time for me to experiment with Gatsby, which is an open source JavaScript framework you can use to build static sites with React.

In this post I’ll walk you through the steps I took to build my blog site from the ground up (sort of), and in the process show you how you can set up a site of your own.

Installing the Gatsby CLI

In order to spin up new Gatsby projects you first need to install the Gatsby CLI. This is provided as an NPM package, which you can install globally on your machine by running the following command:

npm install -g gatsby-cli

If (like me) you prefer Yarn over plain old NPM, you can achieve the same thing with the following command:

yarn global add gatsby-cli

I’ll be using yarn over npm throughout this post - so you may need to substitute as necessary.

If this step hasn’t worked for you, or you’re not sure what I’m talking about, then you’ll want to go and grab an up-to-date version of Node.

If you’re not all that comfortable with web development in general then I recommend running through the first part of the official tutorial on the Gatsby site, which you’ll find here. This talks you through installing Node, Git, the Gatsby CLI, etc. in a little more detail.

Creating the project

One of the great things about Gatsby is that it has a huge library of ready-to-use starter projects for a whole host of different use-cases.

For my blog I used the gatsby-starter-blog template, which at the time of writing is (somewhat unsurprisingly) the most popular starter on the site.

To scaffold the project using this template, first launch a command line and navigate to the directory you’d like your project folder to sit in. Then, run the following command (you can replace blog with whataver you’d like your project folder to be called):

gatsby new blog

This will clone the starter template into the blog directory (or whatever you called it) and run a few setup commands. Once it completes, navigate to the project directory and run yarn start to boot the application in development mode.

After a few moments it should finish spinning up, and your terminal should display something like the following:

You can now view blog in the browser.


Opening the resulting URL in your browser should bring up the generated site:

Gatsby Starter Blog

Ripping out the defaults

You now have a fully functioning starting point on which to build your blog, but before you do anything else you’ll need to go through and rip out the defaults.


The first file to look at is the top-level gatsby-config.js file, which defines your site’s metadata, plugins, and other general configuration.


Most of the values you’ll want to tweak are defined in the siteMetadata section towards the top of the file.

Here’s how I set mine up:

siteMetadata: {
  title: ``,  author: {
    name: `Alex Potter`,    summary: `I use this blog to write about the random coding experiments I embark on in an attempt to learn new things.`,  },
  description: `A software development blog by Alex Potter. I use this blog to write about the random coding experiments I embark on in an attempt to learn new things.`,  siteUrl: ``,  social: {
    twitter: `ajp_dev`,  },

The title field impacts the header text shown on the homepage, and the title of each page on your site (as shown on your browser window/tab). It also influences SEO to some extent.

The author section defines a name and summary field, which are both pulled through and rendered in the <Bio /> component (which we’ll look at next).

The description field acts as the default meta description for the site (which factors into SEO). MDN provides a good reference for these sorts of things if you want to learn more.

The twitter property of the social section should be set to your Twitter handle (without the @).


Further down in the file you’ll find the configuration settings for the gatsby-plugin-manifest plugin, which is involved in enabling PWA support for your site.

For reference, I set the values as follows:

  resolve: `gatsby-plugin-manifest`,
  options: {
    name: `Blog |`,    short_name: ``,    start_url: `/`,
    background_color: `#ffffff`,
    theme_color: `hsl(245, 92%, 60%)`,    display: `minimal-ui`,
    icon: `content/assets/gatsby-icon.png`,


Next, you might want to take a look at the src/components/bio.js file. This defines the <Bio /> component, which gets rendered at the top of the home page, and at the bottom of blog posts.

I wasn’t particularly keen on the default wording so I tweaked it to my liking. In particular, I changed the main paragraph to the following:

  Hi, I'm <strong>{}</strong>. {author.summary}
  <br />
  Hit me up on Twitter <a href={`${social.twitter}`}>@{social.twitter}</a>

You may find that you’re happy enough with the <Bio /> component as it is, in which case feel free to leave it alone.


By this point the site should be feeling a little more personalised:

Modified Blog (1)

The next obvious change is to swap out the default profile picture. To do this, simply replace the content/assets/profile-pic.jpg file with your own image.

I had a .jpg file to hand, so was able to directly replace the file without renaming it. If you use a different file name you’ll need to open up src/components/bio.js again and replace any references to profile-pic.jpg with the name of your new file.


Another obvious change is to swap out the default favicon and replace it with your own image.

To do this, simply delete the content/assets/gatsby-icon.png file and add your own image in its place (I decided to use my profile picture). Then, go back to gatsby-config.js and replace any references to the old file with the name of your new file.

In particular, you’ll want to change the icon property in the settings for the gatsby-plugin-manifest plugin, like so:

  resolve: `gatsby-plugin-manifest`,
  options: {
    name: `Blog |`,
    short_name: ``,
    start_url: `/`,
    background_color: `#ffffff`,
    theme_color: `hsl(245, 92%, 60%)`,
    display: `minimal-ui`,
    icon: `content/assets/icon.png`,  },


With your face plastered all over it, the site should now be feeling like your own:

Modified Blog (2)

The next thing to consider changing is the footer, which by default displays a little shout-out to Gatsby.

To change this you just need to open up src/components/layout.js and modify the contents of the <footer /> tag towards the bottom of the file.

For example:

<footer>© {new Date().getFullYear()}</footer>

Overhauling the styling

By this point you should have ripped out or replaced any relevant default values from the starter template. If you want you can leave it at that and start writing up some posts, but if you’re like me you’ll want to tweak the look and feel a bit first.


The starter template uses a library called Typography.js to provide some out-of-the-box styling for the site. Typography works around themes, and by default the Wordpress2016 theme is used.

If you’re not a big fan of the default theme, have a quick scan through the available themes on the Typography website and decide which one you like the most.

Once you’ve found one you like, go ahead an install the relevant NPM package. I quite liked the feel of the Github theme, so I installed it with the following command:

yarn add typography-theme-github

Next, open up src/utils/typography.js and replace the reference to the Wordpress2016 theme with a reference to your newly installed theme.

For example:

import Typography from 'typography';
import Theme from 'typography-theme-github';
Theme.overrideThemeStyles = () => {  return {
    'a.gatsby-resp-image-link': {
      boxShadow: `none`,

delete Theme.googleFonts;
const typography = new Typography(Theme);
// ...

With this done, you can safely remove the Wordpress2016 package from the project by running the following command:

yarn remove typography-theme-wordpress-2016

With the new theme installed your site should now feel quite different:

Modified Blog (3)


The default fonts for the Github Typography theme are quite nice, but you might want to swap them out if you have favourites of your own. Personally, I really like the Muli (now renamed to Mulish on Google Fonts) and JetBrains Mono fonts.

By default, the project has the Merriweather and Montserrat fonts installed via the typeface-merriweather and typeface-montserrat NPM packages.

Many popular fonts can be installed in this way - just search the NPM website with typeface- followed by the name of the font you’re interested in to see if it’s available.

For example, I found corresponding NPM packages for the fonts mentioned above, and was able to install them with the following command:

yarn add typeface-muli typeface-jetbrains-mono

If you do install some new fonts you’ll need to make sure you add them as imports in the top-level gatsby-browser.js file, so that the relevant font files are served alongside the rest of your site.

I decided I wasn’t going to use the Merriweather font, so I removed it from gatsby-browser.js and added imports for my new fonts, like so:

// custom typefaces
import 'typeface-montserrat';
import 'typeface-muli';import 'typeface-jetbrains-mono';
import 'prismjs/themes/prism.css';

I then removed the NPM package for the Merriweather font entirely by running the following command:

yarn remove typeface-merriweather

Now that your new fonts are installed and imported you can begin to use them on your site. In particular, you can tweak a number of global font settings by opening up src/utils/typography.js and overriding relevant properties on the Theme object.

I decided to override the header font, body font, and font size:

delete Theme.googleFonts;

Theme.headerFontFamily = ['Montserrat', 'sans-serif'];Theme.bodyFontFamily = ['Muli', 'sans-serif'];Theme.baseFontSize = '18px';
const typography = new Typography(Theme);

I also added the following inline style to a few headers on the site to make use of the JetBrains Mono font:

  fontFamily: `'JetBrains Mono', monospace`,

With a fresh set of fonts your site should now be feeling even more custom:

Modified Blog (4)

General styling

To add some finishing touches to the general look of the site, you may want to go back to src/utils/typography.js and add a few styling overrides to the Theme.overrideThemeStyles return value.

You can set any CSS properties you like here - I chose to tweak some colours and margins a little:

Theme.overrideThemeStyles = () => {
  return {
    a: {      color: 'hsl(243, 94%, 70%)',    },    'a.gatsby-resp-image-link': {
      boxShadow: `none`,
    h1: {      borderBottom: 'none',    },    h2: {      borderBottom: 'none',    },    hr: {      opacity: 0.5,    },    strong: {      fontWeight: 700,    },  };

Stylistic features

At this point your site should be nicely personalised to your liking. Again, you could stop here and call it a day, but there are some nice stylistic features you can add in a couple of places if you want to.

Reading time indicators

Firstly, you might want to add an indicator to each blog post to let the reader know roughly how long it will take to read (this is something I’ve shamelessly stolen from Dan Abramov’s Overreacted blog).

To do this, begin by adding a new piece of metadata called minutes to each of the blog posts.

For example, at the top of content/blog/hello-world/

title: Hello World
date: '2015-05-01T22:12:03.284Z'
description: 'Hello World'
minutes: '2'---

The idea is to pull this value through in a couple of places - namely the home page and the blog page itself.

First, open up src/pages/index.js and alter the GraphQL query near the bottom of the file to pull through the minutes field:

frontmatter {
  date(formatString: "MMMM DD, YYYY")

(If you’re a little confused by this step I’d recommend reading more about how Gatsby uses GraphQL - essentially it’s just a way of pulling data into your components.)

Next, find the line that renders {} and add a line below it, like so:

  {node.frontmatter.minutes && ' | ' + node.frontmatter.minutes + ' minute read'}</small>

That’s the home page done - you’ll also want to do the same for the blog post component.

Open up src/templates/blog-post.js and do essentially the same thing - modify the GraphQL query and add a line to conditionally render the number of minutes after the date (note that the variable in this component is called post rather than node).

With that done you should see the reading time indicator displayed next to the post date on both the home page and the individual post page.

For example, here’s how the home page looked for me with a reading time on the “Hello World!” post:

Modified Blog (5)


Next, you may want to go one step further and add a little bit of leading text next to the post date, to make it easier for the user to understand at a glance how old/recent a post is.

To do this, you can use an NPM package called timeago.js. Begin by installing the NPM package with the following command:

yarn add timeago.js

You’ll then need to touch the same files as we did for adding the number of minutes, namely the src/pages/index.js file and the src/templates/blog-post.js file.

At the top of each file add an import for the newly installed package:

import * as timeago from 'timeago.js';

Then, simply find the line that renders {} (or {}), and tweak it as follows:

  {timeago.format(} | {}  {node.frontmatter.minutes && ' | ' + node.frontmatter.minutes + ' minute read'}

With that done it should be much easier for the reader to get a sense of how recent (or in this case, old) each post is:

Modified Blog (6)

Code snippets

If you’re planning to write a technical blog, chances are you’re going to have a lot of code snippets in your posts. For that reason it’s worth spending some time supercharging the look of those as well.

Open up the content/blog/new-beginnings/ file and add some inline code and a short code snippet at the top.

This should give you a feel for how things look by default:

Modified Blog (7)

The starter template uses PrismJS to provide the syntax highlighting for code snippets. In particular, it makes use of the gatsby-remark-prismjs plugin.

PrismJS offers a number of themes by default, but there are plenty of others out there which people have written themselves. I quite like the Night Owl theme for VS Code, created by Sarah Drasner, which Sara Vieira has made a PrismJS theme for (available here).

If you have a favourite editor theme you can try searching online to see if someone has made a corresponding PrismJS theme for it. The following steps should be more or less the same regardless of the theme you choose.

First you’ll want to download the main stylesheet file (in my case it was called style.css), and place it in the contents/assets folder with an appropriate name (e.g. prism-theme-night-owl.css).

Next, you should open up this file and credit the author by adding a comment at the top that links back to the GitHub repo (or wherever else) you got it from.

With that done, go ahead and open gatsby-browser.js and replace the stylesheet reference in there with a reference to the the new CSS file:

// custom typefaces
import 'typeface-montserrat';
import 'typeface-muli';
import 'typeface-jetbrains-mono';

import './content/assets/prism-theme-night-owl.css';

At this point you might be happy enough leaving the stylesheet as-is, but if you’re like me you’ll want to make a few modifications.

For consistency I wanted my code snippets to use the JetBrains Mono font. Also, I wanted to apply a slight border radius to soften the sharp corners.

I went back to the downloaded stylesheet and applied the relevant changes to the top-level styles, like so:

pre[class*='language-'] {
  color: #d6deeb;
  font-family: 'JetBrains Mono', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;  text-align: left;
  white-space: pre;
  word-spacing: normal;
  word-break: normal;
  word-wrap: normal;
  line-height: 1.5;

  -moz-tab-size: 4;
  -o-tab-size: 4;
  tab-size: 4;

  -webkit-hyphens: none;
  -moz-hyphens: none;
  -ms-hyphens: none;
  hyphens: none;

  border-radius: 5px;}

Then, I noticed that the defaults for inline code snippets weren’t very pleasant, so I scrolled down to the /* Code blocks */ section and added the following:

/* Custom CSS: */
:not(pre) > code.language-text {
  background-color: hsl(240, 100%, 95%);
  color: hsl(256, 100%, 27%);
  padding: 0.1em 0.4em;
  border-radius: 2px;
  white-space: pre;

a code.language-text {
  text-decoration: underline;

Finally, I wanted line highlighting to look good, so I added the following CSS to the very top of the file (adapted from the CSS provided here):

/* Custom CSS: */
.gatsby-highlight-code-line {
  background-color: hsla(238, 100%, 85%, 0.2);
  display: block;
  margin-right: -1em;
  margin-left: -1em;
  padding-right: 1em;
  padding-left: 0.75em;
  border-left: 0.25em solid hsl(238, 100%, 81%);

.gatsby-highlight {
  overflow: auto;
  margin: 1.5em 0 2em;

.gatsby-highlight pre[class*='language-'] {
  overflow: initial;
  float: left;
  min-width: 100%;
  margin: 0;

If you’ve followed along with these steps your code snippets should now look a whole lot nicer:

Modified Blog (8)

Again, you could stop here and call it a day, but at this point I noticed my code wasn’t formatted quite how I wanted.

The starter template includes a tool called Prettier, which formats your code automatically based on a set of customisable rules. Prettier is most commonly used to automatically format JavaScript files, but it also formats JavaScript code snippets in markdown files.

My Prettier settings clearly weren’t how I wanted them, so I decided to change them. To do this, I simply opened up the .prettierrc file at the root of the project and tweaked the options to my liking:

  "arrowParens": "avoid",
  "semi": true,  "printWidth": 100,  "singleQuote": true}

Then I ran the following command to format all my files using the new settings:

yarn format

Next steps

If you’ve made it this far you should now have a site that is fully personalised and styled to your liking. So, what’s next?

In a future post I’ll look at how you can set up continuous deployment for your blog site, to make it quicker and easier to publish new content.

Hi, I'm Alex. I use this blog to write about the random coding experiments I embark on in an attempt to learn new things.
Hit me up on Twitter @ajp_dev
© 2020