Hugo is a static site generator (SSG) written in Go (aka Golang), a high-performance compiled programming language often used for developing backend applications and services.

Today, Hugo is capable of generating most websites within seconds (<1 ms per page). That explains why Hugo bills itself as “the world’s fastest framework for building websites.”

In this article, we’ll take a look at the history of Hugo, what makes it so fast, and how you can start building your own Hugo static site.

What Is Hugo? And Why Is It Popular?

Screenshot of Hugo's homepage.
Hugo’s website homepage.

Steve Francia originally developed the Hugo static site generator in 2013, and Bjørn Erik Pedersen took over as the project’s lead developer in 2015. Hugo is an open-source project, which means its code can be viewed and improved on by anyone.

As a static site generator, Hugo takes Markdown content files, runs them through theme templates, and spits out HTML files that you can easily deploy online – and it does all of this extremely quickly.

In 2021, there are dozens, if not hundreds, of static generators. Every static site generator has its appeal. Jekyll is popular among Ruby developers, and while it’s not as fast as other options, it was one of the first static site generators to see widespread adoption. Gatsby is another popular SSG that’s well-suited for developing statically deployable sites that are dynamic in functionality.

So, with so many SSGs out there, what makes Hugo stand out?

Hugo Is Fast

In terms of raw performance, Hugo is the best static site generator in the world. Compared to Jekyll, Hugo was shown to be 35x faster by Forestry. Similarly, Hugo can render a 10,000-page site in 10 seconds, a task that would take Gatsby over half an hour to complete. Not only is Hugo the fastest SSG in terms of build times, but it’s also quick to install.

Hugo ships as a self-contained executable, unlike Jekyll, Gatsby, and other SSGs requiring installing dependencies with a package manager. This means you can download and use Hugo immediately without having to worry about software dependencies.

Templating Is Easy in Hugo

In SSG lingo, “templating” refers to the process of adding placeholders for dynamic content insertion within an HTML page. To access the title of a page, you can use the {{ .Title }} variable. Thus, within a Hugo HTML template, it’s common to see the {{ .Title }} wrapped in H1 tags like so:

<h1>{{ .Title }}</h1>

At build time, Hugo will automatically grab the title within a content file and insert the title between the two <h1> tags. Hugo has a variety of built-in templating variables, and you can even write custom functions to process data at build time. For templating, Hugo uses Go’s built-in html/template and text/template libraries. This helps cut down on application bloat because Hugo doesn’t need to install third-party libraries for templating.

How to Install Hugo

Hugo ships as a compiled executable, which means you won’t have to download and manage many dependencies just to get started. It’s available for macOS, Windows, and Linux.

How to Install Hugo on macOS and Linux

The recommended installation method for macOS and Linux requires Homebrew, a package manager for installation and updating applications. If you don’t already have Homebrew installed, you can install it by running the command below in Terminal:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

After Homebrew has been installed, run the command below to install Hugo:

brew install hugo

How to Install Hugo on Windows

For Windows users, Hugo can be installed using either the Chocolatey or Scoop package managers. Since the instructions for installing Chocolatey and Scoop are a bit more complex than Homebrew, we recommend referring to their official documentation pages here and here.

After installing either Chocolatey or Scoop, you can install Hugo using one of the following commands (depending on your package manager):

choco install hugo-extended -confirm
scoop install hugo-extended

How To Verify that Hugo Is Installed Correctly

To verify that Hugo has been correctly installed, run the following command:

hugo version

This Terminal command should output information regarding the currently installed version of Hugo like so:

hugo v0.85.0+extended darwin/arm64 BuildDate=unknown

Hugo Commands and Configuration

Before we dive into creating a static site with Hugo, let’s get familiar with its various CLI commands and configuration file parameters.

Hugo CLI Commands

  • hugo check – runs various verification checks
  • hugo config – displays the configuration for a Hugo site
  • hugo convert – converts content to different formats
  • hugo deploy – deploys your site to a cloud provider
  • hugo env – displays the Hugo version and environment information
  • hugo gen – provides access to various generators
  • hugo help – displays information about a command
  • hugo import – lets you import a site from another location
  • hugo list – displays a list of various content types
  • hugo mod – provides access to various module helpers
  • hugo new – lets you create new content for your site
  • hugo server – starts a local development server
  • hugo version – displays the current Hugo version

The Hugo CLI also has a variety of flags to specify additional options for some commands. To view a complete list of Hugo flags (there are a lot of them), we recommend using the hugo help command to display a list of all the available flags.

The Hugo Configuration File

Hugo’s configuration file supports three formats: YAML, TOML, and JSON. Likewise, the Hugo configuration file is config.yml, config.toml, or config.json, and you can find it in the root directory of a Hugo project.

An image of the hugo configuration file
Hugo configuration file.

Here’s what a typical Hugo configuration file in YAML format looks like:

DefaultContentLanguage: en
theme:
- kinsta-static-site
contentdir: content
layoutdir: layouts
publishdir: public
paginate: 5
title: Kinsta Static Site
description: "This is a static site generated with Hugo!"
permalinks:
post: :slug/
page: :slug/
tags: "tag/:slug/"
author: "author/:slug/"

If you’ve used WordPress or another CMS before, some of the configuration options may look familiar to you. For example, kinsta-static-site is the name of the site’s theme, Kinsta Static Site is the SEO meta title, and paginate (the number of posts per page) is 5.

Hugo has dozens of configuration options, all of which you can explore in the official Hugo documentation. If you need to make any global configuration change while developing a Hugo site, chances are you’ll need to edit this configuration file.

How To Create a Hugo Site

Now that we’ve gone through how to install and use the Hugo CLI and the basics of the Hugo configuration file, let’s create a new Hugo site.

To create a Hugo site, use the command below (feel free to change my-hugo-site to something else if you’d like):

hugo new site my-hugo-site
Creating a new hugo static site
Create a new Hugo site.

Next, navigate to the site folder, and you should see the following files and folders: config.toml file, archetypes folder, content folder, layouts folder, themes folder, data folder, and static folder. Let’s quickly go over what each of these files and folders is.

Hugo’s config.toml File

As we highlighted above, Hugo’s primary configuration file contains global settings for your site.

Hugo’s Archetypes Folder

The archetypes folder is where you store content templates formatted in Markdown. Archetypes are especially useful if your site has multiple content formats. With Hugo archetypes, you can create a template for each content type on your site. This lets you pre-populate generated Markdown files with all the necessary configuration settings.

For example, if you have a podcast content type for displaying your podcast episodes, you can create a new archetype in archetypes/podcast.md with the contents below:

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

With this podcast archetype, you can then use the command below to create a new post:

hugo new podcast/s1e6_interview-with-kinsta-ceo.md

Now, if you open the newly created post, you should see this:

---
title: "Interview with Kinsta CEO"
date: 2021-05-20T13:00:00+09:00
description: ""
Season: 1
episode: 6
draft: true
---

Without archetypes, you would have to manually specify the front matter parameters for every new post you create. While archetypes may seem complex and unnecessary at first, they can end up saving you a lot of time in the long run.

Hugo’s Content Folder

The content folder is where your actual post content goes. Hugo supports both Markdown and HTML formats, with Markdown being the more popular option due to its ease of use. In addition to being the general storage space for posts, you can use the content folder to organize post content further.

Hugo treats each top-level directory in the content folder as a content section. Content sections in Hugo are similar to custom post types in WordPress. For example, if your site has posts, pages, and podcasts, your content folder would have posts, pages, and podcasts directories where content files for these different post types would live.

Hugo’s Layouts Folder

The layouts folder contains HTML files that define the structure of your site. In some cases, you may see a Hugo site without a layouts folder because it doesn’t have to be in the project’s root directory and can reside within a theme folder instead.

Similar to WordPress themes which use PHP for templating, Hugo templates consist of base HTML with additional dynamic templating powered by Golang’s built-in html/template and text/template libraries. The various HTML template files required for generating your site’s HTML markup are in the layouts folder.

Hugo’s Themes Folder

For sites that prefer a more self-contained way of storing template files and assets, Hugo supports a themes folder. Hugo themes are similar to WordPress themes in that they’re stored in a themes directory and contain all the necessary templates for a theme to function.

While some Hugo users prefer keeping theme-related files in the project’s root directory, storing these files within the themes folder allows for easier management and sharing.

Hugo Data Folder

Hugo’s data folder is where you can store supplemental data (in JSON, YAML, or TOML format) that is needed to generate your site’s pages. Data files are beneficial for larger data sets that may be cumbersome to store directly in a content or template file.

For example, if you wanted to create a list of USD inflation rates from 1960 to 2020, it would take around 80 lines to represent the data (one line for each year). Instead of putting this data directly in a content or template file, you can create it in the data folder and populate it with the necessary information.

Hugo Static Folder

Hugo’s static folder is where you store static assets that don’t require any additional processing. The static folder is typically where Hugo users store images, fonts, DNS verification files, and more. When a Hugo site is generated and saved to a folder for easy deployment, all files in the static folder are copied as-is.

If you’re wondering why we didn’t mention JavaScript or CSS files, it’s because they’re often dynamically processed via pipelines during site development. In Hugo, JavaScript and CSS files are commonly stored within the theme folder because they require additional processing.

How To Add a Theme to a Hugo Site

Downloading and installing a premade theme is a great way to get started with Hugo. Hugo themes come in all shapes and sizes, and many of them are available for free on the official Hugo theme repository. Let’s go ahead and install the popular Hyde theme on our Hugo site.

First, navigate to your project’s theme folder in Terminal:

cd <hugo-project-directory>/themes/

Next, use Git to clone the Hyde theme into your project’s themes directory.

git clone https://github.com/spf13/hyde.git

Next, add the following line to your config.toml file to activate the Hyde theme:

theme = "hyde"

At this point, the Hyde theme is installed and configured. The next step is to start up Hugo’s built-in development webserver to view the site in your web browser.

How To Preview a Hugo Site

Hugo ships with an integrated webserver for development purposes, which means you don’t need to install a third-party webserver like Nginx or Apache just to view your site locally.

To start Hugo’s webserver, run the command below in the root directory of your project:

hugo server -D

Hugo will then build your site’s pages and make them available at http://localhost:1313/:

A Hugo local development server image
Hugo local development server.

If you visit the URL in your web browser, you should see your Hugo site with the Hyde theme:

Hugo site with the Hyde theme.
Hugo site displaying with the Hyde theme.

By default, Hugo’s local development server will watch for changes and rebuild the site automatically. Since Hugo’s build speed is so fast, updates to your site can be seen in near-real-time – something that’s rare to see in the static site generator world. To demonstrate this, let’s create our very first post in Hugo.

How To Add Content to a Hugo Site

Adding content to a Hugo site is very different from a full-fledged CMS like WordPress or Ghost. With Hugo, there is no built-in CMS layer to manage your content. Instead, you’re expected to manage and organize things as you see fit.

In other words, there’s no explicitly “correct” way to do content management in Hugo. We’ll share one method of adding and managing content in this section, but feel free to change things up as you get more familiar with Hugo.

Content Sections in Hugo

In Hugo, the first content organization tool that you have at your disposal is the content section. A content section in Hugo is similar to a post type in WordPress – not only can you use it as a content filter, but you can also use it as an identifier when creating custom themes.

For example, if you have a blog content section folder, you can use it to store all your blog posts and render a specific page template that only applies to blog posts.

How To Add Posts in Hugo

With that in mind, let’s create a content section for blog posts and add a few pieces of content. Create a new folder named posts in your project’s content folder – this is the content section.

Let’s create another organizational layer inside the posts folder by creating a 2021 folder. At this point, your content directory should look like this:

Image of the higo content directory.
Hugo content directory.

Now, let’s create our first post. As we discussed earlier, Hugo supports both Markdown and HTML files for content. In general, it’s better to stick to Markdown files because they’re easier to write, format, and read.

In the content/posts/2021 folder, create a new file that ends in .md (the Markdown file extension). You can name the file whatever you want, but the recommended syntax for naming a Hugo content file is YYYY-MM-DD-a-sample-post.md.

In addition to manually creating a content file, you can also use the Hugo CLI to create a new post with the command below (be sure to run the command from your project directory):

hugo new posts/2021/2021-08-30-a-sample-post.md

Notice how the content folder is missing from the path above. This is because Hugo assumes all content files will go into the content folder by default.

If you open up the newly created content file, you should see a few lines of metadata at the top of the document that looks something like this:

---
title: "2021 08 30 a Sample Post"
date: 2021-08-30T13:44:28+09:00
draft: true
---

This metadata, which is formatted in YAML, is called the “front matter.” Auto-generated front matter is one significant benefit of using the Hugo CLI. The front matter is where unique data for a post (post name, data, draft status, tags, categories, etc.) is stored. The default format for the front matter can be configured on a per-section basis using archetypes.

Now let’s add some text to the post. When writing a post, always make sure your content is below the front matter like so:

View of a Blog post in Hugo.
Blog post in Hugo.

Once you save the content file, you should see Hugo rebuild your site in Terminal. In the screenshot below, you can see Hugo rebuilt the entire site in 22 ms!

View of a Hugo site rebuild.
Hugo site rebuild.

If you visit your Hugo site in your web browser, you should see the new post.

Hugo site with a post displayed.
Hugo site with a post.

How To Add a Page in Hugo

Now that we’ve added a post to our Hugo site, let’s add a page. Most content management systems, including WordPress, distinguish between posts and pages. Typically, a post is a dated piece of content, while a page consists of evergreen or static content.

To create a page, we first need a page content section. To do this, create a folder named pages in Hugo’s content folder. Afterward, use the command below to add a new “About” page to your site:

hugo new pages/about.md

Notice how the naming convention for pages differs from posts. Unlike posts, pages aren’t tied to a specific date, so it’s unnecessary to include the creation date in the file name.

Now, let’s add some text to the “About” page:

About page in Hugo.
About page in Hugo.

At this point, you should see the About page in your web browser:

About page in the web browser live
About page in the web browser.

Now that we have two content sections — posts and pages — let’s go through how to make a few customizations to the site, such as editing the title and description, adding the About page to the sidebar menu, changing the format of permalinks, and removing pages from the post feed.

How To Change the Site Title and Description

The exact method of changing the site title and description depends on your site configuration and/or active theme. In the case of the Hyde theme, the site title and description can be changed in the Hugo configuration file (config.toml).

We know this because of the following theme code that renders the sidebar:

<aside class="sidebar">
    <div class="container sidebar-sticky">
        <div class="sidebar-about">
            <a href="{{ .Site.BaseURL }}"><h1>{{ .Site.Title }}</h1></a>
            <p class="lead">
            {{ with .Site.Params.description }} {{.}} {{ else }}An elegant open source and mobile first theme for <a href="http://hugo.spf13.com">hugo</a> made by <a href="http://twitter.com/mdo">@mdo</a>. Originally made for Jekyll.{{end}}
            </p>
        </div>
        <nav>
            <ul class="sidebar-nav">
                <li><a href="{{ .Site.BaseURL }}">Home</a> </li>
                {{ range .Site.Menus.main -}}
                <li><a href="{{.URL}}"> {{ .Name }} </a></li>
                {{- end }}
            </ul>
        </nav>
        <p>{{ with .Site.Params.copyright }}{{.}}{{ else }}© {{ now.Format "2006"}}. All rights reserved. {{end}}</p>
    </div>
</aside>

The two parts to focus on are:

{{ .Site.Title }}

And…

{{ with .Site.Params.description }} {{.}} {{ else }}An elegant open source and mobile first theme for <a href="http://hugo.spf13.com">hugo</a> made by <a href="http://twitter.com/mdo">@mdo</a>. Originally made for Jekyll.{{end}}

The handlebars {{ }} are part of Hugo’s templating engine and allow for dynamically generated data in rendered pages. As an example, {{ .Site.Title }} instructs Hugo to check the config.toml file and fetch the value mapped to the Title key.

Since Hugo’s default configuration uses My New Hugo Site as the site title, that’s what the sidebar shows. If we change the site title in config.toml to something else, the change will also reflect on the frontend.

Let’s go ahead and change the title parameter in the config.toml from My New Hugo Site to Kinsta’s Hugo Site.

Changing the site title in Hugo.
Changing the site title in Hugo.

Moving on to the site description, you can see that Hugo’s templating engine supports conditional logic. Translated to plain English, the code below instructs Hugo to check if a Params value is assigned to the description key in the config.toml file. If not, here’s a default string to use instead.

{{ with .Site.Params.description }} {{.}} {{ else }} An elegant open source and mobile first theme for <a href="http://hugo.spf13.com">hugo</a> made by <a href="http://twitter.com/mdo">@mdo</a>. Originally made for Jekyll.{{end}}

Since we don’t have a description configured in the config.toml file, Hugo defaults to rendering “An elegant open source and mobile-first theme for Hugo made by @mdo. Originally made for Jekyll.”

Now let’s update our config.toml file from:

baseURL = "http://example.org/"
languageCode = "en-us"
title = "Kinsta's Hugo Site"
theme = "hyde"

To:

baseURL = "http://example.org/"
languageCode = "en-us"
title = "Kinsta's Hugo Site"
theme = "hyde"
[params]
description = "Kinsta is a premium managed WordPress hosting company."

As expected, the changes are now visible on the frontend as well:

Changing the Hugo site description.
Change the Hugo site description.

How To Remove Pages From the Post Feed

On most blogs, it’s common for the post feed on the homepage to only display posts. By default, the Hyde theme includes all content files in the post feed. To change this behavior, you’ll need to edit the range function in the index.html template, which generates the home page.

Hugo’s range function iterates over a defined set of items and then does something with the data. By default, the Hyde theme’s index.html template ranges over .Site.RegularPages and filters out data such as permalink, post title, and post summary before rendering the HTML.

Since .Site.RegularPages includes all regular pages on Hugo, including both posts and pages, the “About” page is rendered. By changing the range items to .Site.RegularPages "Section" "posts", we can instruct Hugo to only filter through regular pages in the posts section – the content files in the posts folder we created earlier.

Let’s make that change now by editing the template from this:

{{ define "main" -}}
    <div class="posts">
        {{- range .Site.RegularPages -}}
            <article class="post">
                <h1 class="post-title">
                    <a href="{{ .Permalink }}">{{ .Title }}</a>
                </h1>
                <time datetime="{{ .Date.Format "2006-01-02T15:04:05Z0700" }}" class="post-date">{{ .Date.Format "Mon, Jan 2, 2006" }}</time>
                {{ .Summary }}
                {{ if .Truncated }}
                    <div class="read-more-link">
                        <a href="{{ .RelPermalink }}">Read More…</a>
                    </div>
                {{ end }}
            </article>
        {{- end }}
    </div>
{{- end }}

To this:

{{ define "main" -}}
    <div class="posts">
        {{- range where .Site.RegularPages "Section" "posts" -}}
            <article class="post">
                <h1 class="post-title">
                    <a href="{{ .Permalink }}">{{ .Title }}</a>
                </h1>
                <time datetime="{{ .Date.Format "2006-01-02T15:04:05Z0700" }}" class="post-date">{{ .Date.Format "Mon, Jan 2, 2006" }}</time>
                {{ .Summary }}
                {{ if .Truncated }}
                    <div class="read-more-link">
                        <a href="{{ .RelPermalink }}">Read More…</a>
                    </div>
                {{ end }}
            </article>
        {{- end }}
    </div>
{{- end }}

After making this change, the home page will only display posts like so:

Display posts only on the home page.
Display posts only on the home page.

How To Use Partials in Hugo

One of Hugo’s most powerful templating features is partials – HTML templates embedded in another HTML template. Partials allow for the reuse of code across different template files without managing the code in each file.

For example, it’s common to see different page sections (header, footer, etc.) in their separate partial files, which are then called within a theme’s baseof.html template file.

Within the baseof.html file in the Ananke theme, you can see an example of a partial on Line 18 – {{ partial "site-style.html" . }}.

In this case, {{ partial "site-style.html" . }} instructs Hugo to replace the contents of Line 18 with the site-style.html in the /layouts/partials folder. If we navigate to the /partials/site-style.html, we see the following code:

{{ with partialCached "func/style/GetMainCSS" "style/GetMainCSS" }}
    <link rel="stylesheet" href="{{ .RelPermalink }}" >
{{ end }}
{{ range site.Params.custom_css }}
{{ with partialCached "func/style/GetResource" . . }}{{ else }}
    <link rel="stylesheet" href="{{ relURL (.) }}">
{{ end }}
{{ end }}

By offloading this code to a separate file, the baseof.html template file can remain organized and easy to read. While partials are not necessary, especially for basic projects, they come in handy for larger projects with more complex functionality.

How To Use Shortcodes in Hugo

Hugo shortcodes are similar to partials in that they allow for the reuse of code across a variety of pages. Shortcodes are HTML files that reside in the /layouts/shortcodes folder. The main difference is that partials apply to HTML templates, while shortcodes apply to Markdown content pages.

In Hugo, shortcodes let you develop modules of functionality that you can use in pages across your site without managing code changes for each page.

If you run a blog, chances are you’ll need to go through the body content of your posts to update year references to the current year. Depending on how many posts you have on your site, this task can take a long time!

By using a Hugo shortcode in your content files, you won’t have to worry about updating year references ever again!

Let’s start by creating a shortcode in /layouts/shortcodes/current_year.html with the contents below:

{{ now.Format "2006" }}

Shortcodes can be embedded into posts with this syntax – {{< shortcode_name >}}. In our case, we can call the current_year.html shortcode with {{< shortcode_name >}} like so:

---
title: "2021 08 30 a Sample Post"
date: 2021-08-30T13:44:28+09:00
draft: true
---

This post was created in the year {{< current_year >}}.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur finibus, velit sit amet vulputate scelerisque, massa turpis fringilla nulla, commodo dapibus urna arcu at nunc. Mauris ultrices convallis ipsum eget facilisis. Curabitur ut rutrum sem. Praesent id nibh non enim mollis porta. Nam mollis, quam et vehicula tristique, lorem ante laoreet orci, sit amet congue tortor nibh sit amet leo. Curabitur lobortis neque tempor, vestibulum lacus nec, condimentum arcu. Nulla fringilla leo sit amet ipsum auctor sagittis. Vivamus aliquam iaculis posuere. Pellentesque malesuada neque sit amet consectetur fringilla. Curabitur felis tellus, mattis in dui vel, vestibulum tincidunt metus. Mauris eget elit dui. Etiam risus nulla, ultricies vitae molestie quis, placerat in magna. Proin interdum, orci ac auctor ullamcorper, tellus ex porta tortor, suscipit luctus libero odio quis arcu.

Phasellus dapibus pellentesque ex eget pulvinar. Proin vitae elit risus. Sed justo nulla, pellentesque eu erat eu, luctus bibendum magna. Curabitur at mi id augue egestas condimentum sed quis lectus. Aenean fringilla nisl sed tincidunt tristique. Cras scelerisque laoreet sapien a faucibus. Vivamus a vehicula arcu. Duis rutrum, massa eu tincidunt eleifend, est nulla faucibus nisl, sit amet consectetur neque velit at velit. Integer fermentum augue ut orci iaculis aliquet. Ut in gravida magna.

If you view the post in the web browser, you should see the current year in the first line of the post like so:

Use a Hugo shortcode to auto-generate the current year.
Use a Hugo shortcode to auto-generate the current year.

How To Add Images to a Post in Hugo

Unlike WordPress and other full-fledged content management systems, Hugo doesn’t include a drag-and-drop system for managing images. Thus, designing an image management system is offloaded to the end-user.

While Hugo has no standardized way of managing images, one popular method relies on storing images in the /static folder and referencing them in posts and pages using a shortcode. Let’s walk through how you can do basic image organization in Hugo.

The first thing we’ll need to do is create an organizational structure for our image library. While this sounds complex, all that’s required is the creation of a few additional directories within the /static folder.

Let’s start by creating an uploads folder in /static. Within the uploads folder, create a folder named 2021 to hold all the images uploaded in 2021.

Image management in Hugo.
Image management in Hugo.

Next, let’s add two images (blue1.jpg and blue2.jpg) into the 2021 folder.

Adding images to the
Adding images to the “2021” folder.

In HTML, images are displayed using the <img> tag. For instance, to display blue1.jpg, we can use the HTML below:

<img src="/uploads/2021/blue1.jpg" alt="Blue is the warmest color!">

While it’s possible to add this HTML directly to the Markdown content file, it’s better to create a shortcode that you can use to display any image from the uploads folder. This way, if you ever need to update the img tag, you can edit the shortcode template without editing each instance of the img tag.

To create the shortcode template, create a new file at /layouts/shortcodes/img.html with the content below:

<img src="/uploads/{{ .Get "src" }}" alt="{{ .Get "alt" }}

Next, add the shortcode below to a blog post:

{{< img src="2021/blue1.jpg" alt="Blue is also the coolest color!">}

In the shortcode template, {{ .Get "src" }} and {{ .Get "alt" }} instruct Hugo to fetch the contents of the src< and alt< parameters when calling a shortcode.

Now, if you reload the blog post, you should see the image like so:

Example of an image shortcode in Hugo.
Image shortcode in Hugo.

How To Deploy a Hugo Site To Kinsta

At this point, you have learned how to install Hugo, create a site, add a theme, make basic edits to configuration files, and expand the functionality of your site with partials and shortcodes. You should now have a functional site that is ready to be deployed online.

Previously, we used the hugo server -D to spin up a local development server to preview changes to our site in real-time. To generate the site in full, we can use the hugo command in the root directory of our project. After the site generation is complete, you should see a new public folder in your project directory. Inside this folder, you’ll find all the files that need to be uploaded to a static server.

Generate your Hugo site locally.
Generate your Hugo site locally.

The best option to publish your static site is to push your Hugo project to a Git repository and link it to Kinsta’s Static Site Hosting. Currently Kinsta is only able to build SSG’s that are based on Node.js but for SSG like Hugo there are two ways around it:

For this guide, let’s use the Hugo-bin dependency. To do this, initialize Node.js in your Hugo project by running npm init -y command in the root directory of your Hugo project.

This will scaffold a basic package.json file. Next, install the hugo-bin developer dependency:

npm i -D hugo-bin

Next, in your package.json file, add the following script command:

"scripts": {
    "build": "hugo",
    "create": "hugo new",
    "serve": "hugo server"
  }

Now, you can push your code to your Git repository. Once the repo is ready, follow these steps to deploy your static site to Kinsta:

    1. Login or create an account to view your MyKinsta dashboard.
    2. Authorize Kinsta with your Git provider.
    3. Click Static Sites on the left sidebar, then click Add site.
    4. Select the repository and the branch you wish to deploy from.
    5. Assign a unique name to your site.
    6. Add the build settings in the following format:
      • Build command: npm run build
      • Node version: 18.16.0
      • Publish directory: public
    7. Finally, click Create site.

And that’s it! You now have a live, fully functioning static site created with Hugo.

If you ticked the automatic deployment option when deploying your site, whenever you edit your site and push the changes to the Git repository, your repository will automatically trigger a new build and deployment on Kinsta without any manual intervention.

As an alternative to Static Site Hosting, you can opt for deploying your static site with Kinsta’s Application Hosting, which provides greater hosting flexibility, a wider range of benefits, and access to more robust features. For example, scalability, customized deployment using a Dockerfile, and comprehensive analytics encompassing real-time and historical data.

Summary

Hugo is one of the most popular static site generators in the world and for a good reason. Not only does it have super fast build processing, but it also ships with powerful templating capabilities that support partials and shortcodes.

In this tutorial, you learned how to configure Hugo, create a new project, add content files, edit theme files, and deploy a finished static site. We recommend going through the official Hugo documentation to learn more about Hugo and its more advanced features like custom functions, front matter, and CSS/JS buildpacks.

What are your thoughts on Hugo and other static site generators? Please let us know in the comments below!

Brian Li

Brian has been a WordPress user for over 10 years, and enjoys sharing his knowledge with the community. In his free time, Brian enjoys playing the piano and exploring Tokyo with his camera. Connect with Brian on his website at brianli.com.