Hugo is an open source static site generator that is powered by Go - which makes it insanely fast to compile and run.

What is a static site? Well it's the most basic website of all, pure HTML. Hugo as a framework allows you to use templates to generate HTML files quickly.

Let's go over the pros and cons:


  • It allows for variables in the template (using Hugo's own templating engine based on Go)
  • Highly customizable templates and styles
  • At its core - it's just HTML, with batteries
  • Fairly easy to learn
  • Minimization comes included


  • Not popular outside the US
  • Not non-tech friendly - there are no dashboards or WYSIWYG editors for you to make blog posts

Getting Started

Here are the download links:

To get started, hugo generates a very basic site

$ hugo new site quickstart
$ cd quickstart
$ hugo serve
├── archetypes
│   └──  <--- preconfigured files 
├── assets          <--- CSS / Javascript
├── config.toml     <--- site-wide variables
├── content         <--- your pages
├── data            <--- similar to config, but for content
├── layouts         <--- default/custom layouts
├── public          <--- build folder
├── static          <--- where your image assets go
└── themes

Adding CSS and Javascript

The folder /assets is for CSS and Javascript you want to upload to the site, since it uses Hugo Pipes.

Stores all the files which need be processed by Hugo Pipes. Only the files whose .Permalink or .RelPermalink are used will be published to the public directory.

I like to put my SCSS into a folder, and import it in the /layouts/baseof/_default.html file.

This will mean that every page will include the whole CSS file. If you'd like to have something more specific to each page, then add the CSS to the HTML for the specific page you want. We'll get into custom pages later.

Folder structure

├── js
│   └── index.js
└── scss
    ├── _single.scss
    └── main.scss


@import '_single.scss'

_single.scss is just a name. But it is convention to add "_" prefix for CSS partials and import them in the main.

As a cleanliness rule, wrap your CSS partials with a wrapper class so that it doesn't leak outside the intended pages. Especially since all the pages are using the same stylesheet.


{{ $js := resources.Get "js/index.js" }}
{{ $script := $js | resources.Minify }}
<script defer src="{{ $script.Permalink | relURL }}"></script>

{{ $options := (dict "targetPath" "/css/main.min.css" "outputStyle" "compressed" "enableSourceMap" true) }}
{{ $style := resources.Get "scss/main.scss" | resources.ToCSS $options }}
<link rel="stylesheet" href="{{ $style.Permalink | relURL }}">

Note the resources.Minify and resources.ToCSS that is included. That is the magic, that is what helps minify our Javascript and CSS into production ready code. Hugo has a few more in-built pipes that you can play with.

Index.html and Content Pages

/layouts/index.html is a special page that is loaded when we enter the website on i.e. the landing page. Although you can also move index.html to root of /content folder, however you won't be able to use partials outside of /layouts.

The rest of the pages are loaded from /content

└── content
    └── about
    |   └── index.html      // <-
    ├── posts
    |   ├── firstpost.html  // <-
    |   ├── happy
    |   |   └── ness.html   // <-
    |   └── secondpost.html // <-
    └── quote
        ├── first.html      // <-
        └── second.html     // <-


is the basic template for every page, and it usually contains the <head> and <style> declarations.

    {{ block "main" . }}{{ end }}

{{ block "main" . }}
is where your other pages slot in. In other pages you'll likely see a {{ define "main" }}.

is the template for html pages in /content/**/*.html.

contains single partial HTML that can be inserted into other layout pages.

Templating HTML

Templating uses something akin to Go templating handlebars. There are several functions you can use, but most common will be:

These are used to send in HTML partials you've made from /layouts/partials/<filename>.html. A dictionary (object) of values can be sent into a partial by using the dict function

{{ partial "<filename>" (dict "context" . <key> <value> <key> <value>) }}
{{ partial "contact-button" (dict "context" . 
    "text" "Request A Demo" 
    "color" "#ffee33") 

A for-each loop. Ranges require an {{ end }}.

{{ range (where .Site.RegularPages "Section" "blog") }}
{{ .Title }}
{{ end }}

If blocks. Also requires an end.

{{ if eq $variable true }}
    <p>This will show if true
{{ end }}


Frontmatter such as titles and section are listed on the top of the html page within /content. Certain frontmatter params are used for structuring the footer and navbar such as section and subsection.

You can even use HTML in your Frontmatter, as long as you import it correctly in your template.


    title: Software Development
    subtitle: The cake is a lie
bgImageUrl: images/content/people.png
text: "Lorem ipsum dolor sit amet consectetur, adipisicing elit. Exercitationem, placeat ipsa ipsum quaerat optio labore impedit. Non commodi sit nihil magnam temporibus magni laboriosam, velit tempore amet iure ut mollitia."
        <li>Why you can use HTML</li>
        <li>Different ways to use Hugo</li>
        <li>Quality over Quantity</li>
    - imgUrl: images/content/meeting-rules.jpg
    - imgUrl: images/content/profile-search.jpg
    - imgUrl: images/content/reporting.png

Using HTML from Frontmatter

By piping into safeHTML, we can use HTML in our frontmatter

{{ if .Params.longDesc }}<p>{{ .Params.longDesc | safeHTML }}</p>{{ end }}

Global Variables

Any variable that wish to be saved globally can be set in config.yaml under the params key.

You can access the parameter in html using {{ $.Site.Params.[parameter key]}}.


    gtagKey: U-123456


<script async src="{{ $.Site.Params.gtagKey }}"></script>

You can access data files via $.Site.Data.<filename>


    icon: la-handshake
    text: lorem ipsum
    position: CEO
    company: Investment Bank
    icon: la-user-tie
    text: lorem ipsum
    position: Director
    company: Chase Bank


{{ range $.Site.Data.testimonials }}   
    <img class="la {{ .icon }}"/> <h6>{{ .position }} | {{ .company }}</h6>
    <h4>"{{ .text }}"</h4>


Hugo, is easy to learn, quick to develop, flexible enough for customization, yet structured enough for maintenance.

I like it a lot and would recommend it for any static sites that does not require an editor.

© 2024. All Rights Reserved.