Hugo is a static site generator that converts markdown files (.md) to html pages. Let’s discover how we can build a blog using it, and discuss some configuration options that will make the experience better.
Step 1 - “Install” Hugo
- Download the latest extended version for your OS from
- Extract Hugo in a folder of your choice
- (Optional) Add Hugo folder to path - if not, then replace the
hugocommand with the full path to Hugo, ie
Step 2 - Create a new blog
- Launch a new command prompt and navigate to the folder which will contain the new site.
- Create a new hugo using
hugo new site my-blog. A folder named “my-blog” will be created.
- Download a new theme, preferably beatiful hugo.
- Extract and copy the new theme inside
- Rename theme folder from
- Open the config file (
my-blog/config.toml) and edit the theme line
theme = "beatifulhugo"to select the new theme
- Create a new post
hugo new post/first-post.md
- Run the deveopment server (
hugo serve -D -w)
- Preview the new site on http://localhost:1313 - unless port 1313 is already used, in which case the new port will be listed in the development server’s output
Step 3 - Content Management
Although there are a lot of ways to organize content in hugo, I prefer to place each post in a separate folder named
yyyy-mm-dd title, also I like to group these folders by year. Finally since each post lies in each own folder it should be named as
So the full path for each post
This is how my folder structure looks like
my-blog │ ├── cv │ └── index.md │ ├── content │ ├── post │ │ ├── 2018 │ │ │ ├── 2018-03-15 Hugo Gallery Shortcode │ │ │ │ ├── index.md │ │ │ │ └── feature.png │ │ │ │ │ │ │ └── 2018-09-11 Hugo 101 Static Site Generators │ │ │ ├── index.md │ │ │ └── feature.png
That approach both keeps all post files together in a folder and isolates them from the rest posts allowing for easier editing as each time we have to handle only one folder containing exactly what we need.
By default hugo will use the post title to create the url of each posts but this approach might create issues if we decide to change the title of the post or if we don’t necessarily like to match the url with the post’s title. Also since post images will be under the same url, changing post title will require changing all image urls. A better approach is to use “slugs” a slug is a custom url part that we assign to each post.
First we need to instruct hugo to use the slugs so we edit
my-blog\confg.toml and add the following lines
[permalinks] post = "/:year/:slug/"
This instructs hugo to create a url that consists of the year and the slug for each post.
Now in order to set the slug for each post we need to understand what these index.md files contain.
Each post file (
index.md in our case) contains the text of the post and some meta-data, called frontmatter. The frontmatter must appear in the beggining of each file between
--- and consists of name: value pairs. For example the frontmatter of this page is
--- title: "Hugo 102: Setting Up" date: 2019-03-15 tags: ["hugo"] slug: "hugo-setup" image: "2019/hugo-setup/featured.png" ---
the year of the date and the slug are used to construct the url of each post. Note that the image field here will be used in the home page of the post and, thus, it’s value must be relative to the root of blog.
Step 4 - Content
The actual content of each post starts after the front matter. Everything we write bellow the frontmatter will appear in the post’s body. The content should be formatted in markdown but also regular html will work.
As a very short intro to markdown:
- prefixing any line with
#, ##, ###, ####, #####, ######will create headers
- enclosing any text in
* or **will render it using italic or bold
- prexiing any lines with
-will create lists
Step 5 - Generating
By defaut hugo marks all new posts as drafts, before generating check that no post has a
draft: true field in it’s frontmatter
To generate the site use the
hugo command. It will create a folder named
public with all the content of the site. You can publish your site by uploading the contents of the
public to any host.