Setting Up a Website with the Hugo Framework

03 January, 2020

What is hugo?

Hugo is a static JAM generator written in Golang:

Why I switched to Hugo

This site used to run on WordPress, which had a lot of features that are completely unecessary for a simple blog. Hugo opts for a simple and streamlined approach with a tiny set of key functionalities, that can be easily expanded when or if there is ever a need to do so.


A lack of GUI / editor makes Hugo unusable for non-technical people.

Another thing I really dislike about Wordpress is the editor. I feel like I spend more time wrestling with the formatting than I do writing the actual content. With Hugo all content is written in Markdown, which happens to be my favourite tool for creating formatted text.

Lastly, because Hugo produces a static website and doesn’t need a database, the entire website can be stored in Git and served from just about anywhere.

$ git pull
$ hugo -d /path/to/webroot/

Install Hugo and initialize a new site

Install Hugo (i’m using brew):

$ brew install hugo

Verify installation:

hugo version

Create a folder for your Hugo project and initialize a new site called personal-blog:

$ mkdir website && cd website
$ hugo new site personal-blog

Congratulations! Your new Hugo site is created in /path/to/project/personal-blog

We now have a folder called personal-blog that houses the code for the website.

A comprehensive explanation of the folder structure can be found here.

Install a theme

While Hugo has a robust built-in theming engine, i encourage you to start by picking one of the hundreds of pre-made themes found here.

Installing and swapping between themes in Hugo is very simple: Just move the source files to the themes/ folder located in the project’s root directory.

For this guide we will be using a theme called Manis.

// Git clone theme from source

$ cd themes/
$ git clone

Cloning into 'manis-hugo-theme'...
remote: Enumerating objects: 55, done.
remote: Counting objects: 100% (55/55), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 1064 (delta 18), reused 35 (delta 11), pack-reused 1009
Receiving objects: 100% (1064/1064), 1.43 MiB | 2.83 MiB/s, done.
Resolving deltas: 100% (522/522), done.

To activate the theme, we need to add it’s name to configuration.toml:

$ echo 'theme = "manis"' >> configuration.toml

Start local developement server

To see the website in action, let’s start a local Hugo development server:

$ hugo server -D

                   | EN  
  Pages            |  7  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  7  
  Processed images |  0  
  Aliases          |  0  
  Sitemaps         |  1  
  Cleaned          |  0  

Built in 4 ms
Watching for changes in /path/to/project/personal-blog/{archetypes,content,data,layouts,static,themes}
Watching for config changes in /path/to/project/personal-blog/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address
Press Ctrl+C to stop

The -D flag tells Hugo to include pages marked as drafts.

Hugo will watch your project directory, and rebuild the site whenever changes are detected.

Add content

Time to add some content. Create a new folder called blog/ inside the content folder:

$ mkdir content/blog
$ hugo new page blog/
/path/to/project/personal-blog/content/posts/ created

This will create a new Markdown file under /content/blog/ called

Let’s take a look at the structure of that file:

title: "My First Post"
date: 2019-03-26T08:47:11+01:00
draft: true

Data contained between the lines is called front matter, and contain arbitary meta-data about the post, that can be accessed by in templates.

Set up navigation

You might notice we don’t yet see our newly created post anywhere.

This is because most themes have their own default configurations, that might not line up with your naming scheme.

Fix this by first overriding the default config with the theme’s config.toml.

Now find the [menu] block. Here’s what it looks like in the Manis theme:

                name = "Post"
                url = "/post/"

                name = "About"
                url = "/about"

You migh have already have figured out that each file and folder starting from content/ corresponds to their respective URL paths.

Here’s some examples to illustrate how the folder strucutre corresponds to url paths. The slugs can be set in the post’s front matter as well, so the name of the file doesn’t necessary matter.

/about/            -->  content/
/posts/blog-post/  -->  content/blog/
/guides/hugo/post/ -->  content/guides/hugo/

You should be able to access the /posts/ route now.

Deploy the site

Hugo produces a static HTML-bundle, so the site can be hosted from almost anywhere. Figuring out the hosting solution is left as an exercise to the reader, but i recommend using this command for compiling the bundle:

$ hugo --minify -d build


Hugo is a great solution for people who want their website’s to be simple, efficient and hassle free.

If your page needs to do complex DOM manipulation, track state, or serve highly dynamic and changing content, then Hugo probably isn’t the best tool for the job (try Next.js instead).

Hugo is also likely to be too difficult to be used by non-techincal people, so if you want the marketing department to take care of the content input, maybe just stick to Wordpress.