How to build a blog using Hugo and Netlify

I wanted to set a fun project for myself to learn some new technologies, and decided this time I wanted to learn a bit about Static Site Generators (SSGs).

Goal: Build a blog built by an SSG and deployed any time the code repsository changes. (You can see the result at


One area that took me some time to comprehend was why I would use a static site, if I already had a CMS. There were so many articles online about using an SSG with a headless CMS…but why? Best I can tell, the benefits were simply that a developer will have more flexibility using familiar frameworks such as React or Vue, while using a CMS to handle all content. However, as I am by no means a frontend developer, I was close to scrapping this project, as I thought “Oh well, I should just use Ghost - it’s only $5/month, and is an all-in-one platform to serve content as well as manage the content”.

However, I really wanted to try to learn something new, and see if I can just deploy a blog for free using just Markdown.

As I always end up doing, something that I was hoping to take a few hours, took on quite a bit more time as I went down the rabbit hole of research into various technologies. I played around with several different technologies, such as (not all of these are SSGs, more on that later):

Selecting Hugo

I won’t go in too much detail on all of the technologies I looked at, but in general, I found Hugo to be super quick to set up and build, and just the SIMPLEST of all the options. While I know this is similar to Jekyll, I really just didn’t want to deal with configuring a Ruby environment, and the speed of Hugo left everything else in the dust.

So what actually is a Static Site Generator?

In short, an SSG is a framework designed to manage your website and transform your website into a site serving only static pages.

Getting Started

For this exercise, let’s build a static blog hosted by Netlify (free!).

Note: I’ll be using PowerShell on my Windows box for this tutorial, so please recall that if copy/pasting.


High level flow

  1. Download/Install Hugo
  2. Create a Hugo project
  3. Add and configure a theme
  4. Add to Git
  5. Deploy to Netlify

Download or install Hugo

To install Hugo, I went over to their GitHub Releases page and downloaded their standalone Windows x64 binary and placed it in my Projects directory, where we will be creating our site (you can always install it properly/add the binary to your PATH, but I wanted quick).

Creating the site

To create a new site, simply run the below commands:

.\hugo.exe new site hugo-blog
mv .\hugo.exe .\hugo-blog
cd .\hugo-blog
.\hugo.exe server -D --gc

We now have our project created, and have just started the Hugo server. We used the -D flag to tell Hugo to show draft content, and I typically add in –gc to ensure that cleanup is run each time by clearing the cache. You can access your site at http://localhost:1313.

Understanding the directory structure

You should now see the following directory structure:

|__assets *this will not show up by default
|__config *this will not show up by default

Adding your first theme

For this blog, we will use the tale theme for Hugo. Run the following commands from the root of the project:

git submodule add .\themes\tale

We will NOT be editing any files from the theme, but will make all modifications in the layouts folder discussed above. This will let us always update the submodule to update our theme without worry that we will overwrite any changes we have made.

To initialize the theme, edit the config.toml in your root directory and add the following lines (while also editing the defaults):

# Theme Settings
theme = "tale"
  Author = "Aaron Katz" # Add the name of the author (this theme only supports one author)
  name = "Caliburn Security" # Used by the foot copyright

There we go, the theme is now active! (Note that in many cases, themes will require you to copy and paste the theme’s theme.toml file into your config.toml)

Go ahead and check out your page - every time you save a file Hugo rebuils the site live!

Modifying theme files

One issue with the current theme is that non-post content will be displayed in the homepage list. To change this, let’s copy the .\themes\tale\layouts\index.html page to .\layouts\index.html. Once there, replace: {{range (.Paginate .Site.RegularPages).Pages}} with {{ range where .Paginator.Pages "Section" "post" }}. This will ensure only the “post” section will be displayed in the list.

Adding Google Analytics

I also wanted to add some Google Analytics to my blog, and I noticed the theme didn’t incorporate this functionality. Luckily, Hugo makes adding analytics extremely simple. Open up the config.toml file and add the following line:

googleAnalytics = "" # The UA-XXX number from Google Analytics

Once the configuration is saved, copy the .\themes\tale\layouts\partial\head.html file to .\layouts\partial\head.html and add the following code right below the head tag:

{{ template "_internal/google_analytics_async.html" . }}

There we go, now we have Google Analytics working!

Writing Content

Let’s add a nice About page so people know everything there is about me!

.\hugo.exe new

To ensure that this page is added to the main menu, add the following line to the page’s front matter: menu: main.

Note: To build Hugo, which will generate the content under the .\public folder, simply run .\hugo.exe

Front matter

This was a new term for me. Essentially, front matter is just structured metadata for your content. By default, your template will add the following metadata fields to each page or post you create:

Other potentially useful front matter elements are:

Creating an archetype for blog posts

Let’s go ahead and change the default front matter we see for blog posts. In the archetypes folder, create a new file called and add the following:

title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true

slug: {{ .File.BaseFileName }} # Will take the filename as the slug. Feel free to change this to any format you like.  I like including this, so that I remind myself I have the option to change if I want.

summary: "" # Remove this if you want Hugo to just use the first 70 (configurable) characters of the post as the summary.
description: ""

# Lists

Now let’s do one final build with .\hugo.exe and get ready to configure our Git repository!

Configure git

Time to configure the project for git

git init
git remote add origin <YOUR GIT URL>
git push -u origin master


Now that we have our site stored in git, it’s time to deploy! To save on the length of this post, I will be writing a new article in this series on how to deploy to Netlify in under 10 minutes!


Whew! A lengthy blog post, but hopefully this shows how quickly it is to get up and running with a “serverless” blog. Let’s see what I learned :)

What I loved


What’s next?

Next up I will explore how I can add SEO to Hugo websites, enable multiple authors, a table of contents, add search and comments, and possibly add a headless CMS as well.

So do I need a CMS?

After all of this, I still had this question in the back of my mind. And the answer is, “it depends”. If I were to incorporate a lot of media, such as images or videos that I need to upload, it will certainly get tedious adding and organizing them all to the images folder in static. At that point, I would look into a headless CMS such as Ghost, Netlify, or Sanity to manage the content, as long as I could still write my posts using Markdown.


comments powered by Disqus