Hugo Tutorial: How to Build & Host a (Very Fast) Static E-Commerce Site

In a rush? Skip to tutorial steps or GitHub repo + live demo.

Time to dive into the fast-moving world of JAMstack & static web development once again! Our previous posts on handling e-commerce with static site generators such as Middleman and Jekyll were quite successful, so why stop there, huh?

Ladies and gentlemen, today, we're going to prove how easy it is to set up e-commerce on static sites once again. And this time, we'll use an in-depth Hugo website tutorial to do so. :)

The following guide will show you:

  1. How to build your static site using Hugo's site generator;
  2. How to (easily) integrate Snipcart's shopping cart platform on top of it;
  3. How to deploy your Hugo e-commerce site on Netlify.

But first, a word on the pivotal tool we're going to use throughout this.

Hugo: a FAST Golang static site generator

hugo-static-site-generator-logo

Hugo could mean different things to different people. Bookworms might think of Les Misérables' legendary author. Cinephiles might think of the little boy in Scorsese's 2011 film. But if you're a developer (if you're reading this, you probably are), here's what you should be thinking*: blazing fast & modern static website engine.

Written in Go by Steve Francia aka spf13, Hugo comes off as one of the most efficient ways we've seen to build, manage and update modern static sites. It's easy to install on any platform, plus you can host it anywhere—we suggest Netlify, as you'll see later. And its build times are just off the charts (~1 ms per page).

Today, I'll show you how to use Snipcart and Hugo to build an old school Star Trek shop on a static site. Why Star Trek, you ask? Because we already did Star Wars.

Psst: still wondering what the heck static site generators are and why they matter? Give Eduardo Bouças' intro post a read.

Hugo tutorial: site, products, templates & deployment

1. Installing Hugo & building your new static website

First of all, you need to install the generator on your computer and create a new website. It'll take you maybe 10 minutes, following the Hugo Quickstart documentation. Or, if you're as fast as Dan Hersam, 2 minutes:

Once you've downloaded the appropriate version on Hugo's GitHub repo, installation is a breeze (as explained in the docs above). So let's focus on creating the new Hugo site.

We'll use the appropriate CLI command to do just that:

hugo site new snipcart-hugo

Architecture

This command will generate a basic skeleton for your project. You should have a site directory that looks like this:

│   config.toml
│   
├───archetypes
├───content
├───data
├───layouts
├───static
└───themes

The config.toml file will contain the site settings. For our demo, we won't need to explore this too much, as we'll be doing something fairly simple with the site itself.

It's not necessary to go too deep into the inner workings of Hugo here. Basically, during this tutorial, we'll be creating files in the data folder, which is used to store additional data that might be used to generate the site.

We're also going to add some templates in the layouts folder, which is the default location to store Hugo templates.

The static folder can be used to store any static assets such as CSS, JavaScript files or images. In our demo, we'll add an images folder containing our product images.

Of course, we advise you to get a little familiar with the Hugo documentation before looking into a full-fledged Snipcart integration.

Themes

We also decided not to install any specific theme for this demo (we’ll use a CSS framework to style our site later on), but there are many open source themes available. This post discusses how to set up themes on your Hugo website, so you might want to give it a read. It also explores basic site creation with Hugo in more details (Hello World, blog, photo gallery, etc.).

You can also check out the official repository for some of the best Hugo themes here.

2. Creating a static JSON file for our store's products

Okay! Now, let's set up our products: a Klingon dictionary and a phaser. We could have used a headless or static CMS for this part (we've done it before). But for the humble purpose of this post, we're going to create a static .json file to contain our products.

Hugo provides a very neat function called getJSON. It can be very handy when some of your data comes from either a headless CMS or any API that returns JSON.

Hugo provides a very neat function called getJSON. It can be very handy when some of your data comes from either a headless CMS or any API that returns JSON. As our JSON file is directly in the data folder we could have used .Site.Data.Products instead of calling the getJSON method, but here we wanted to show that it's also possible to interact with a remote API.

We'll need to put a new file named products.json in the data folder.

[{
    "id": "1",
    "name": "Klingon dictionary",
    "price": 34.87,
    "image": "/images/dictionary.jpg",
    "description": "nIvbogh tlhIngan dictionary qaStaHvIS veng SuvwI'",
    "url": "http://snipcart-hugo.netlify.com"
}, {
    "id": "2",
    "name": "Captain Kirk Phaser",
    "description": "The Original Series Phaser comprises a small, hand-held Type I Phaser, which slots into a larger Type II Phaser body with a removable pistol-grip.",
    "price": 145.98,
    "image": "/images/phaser.png",
    "url": "http://snipcart-hugo.netlify.com"
}]

3. Generating your Hugo templates

Next step is to set up the different layouts for our site. The most important is the header template, where we'll add the Snipcart dependencies.

We'll also create a main template where we'll loop inside of our products to show a summary and add a Snipcart "buy button".

Note: Snipcart products are defined directly in the HTML markup with simple data attributes. Details here.

In the layouts folder, we'll put a new index.html template. This file will be used as default and will be the first one generated by Hugo.

layouts/index.html
{{ partial "header.html" . }}

{{ $products := getJSON "/data/products.json" }}

<section class="container">
    <div class="row">
        {{ range $products }}
            {{ partial "product.html" . }}
        {{ end }}
    </div>
</section>

{{ partial "footer.html" }}

At the beginning of the post, we wrote about the getJSON method. We're going to use this in our index.html template.

We'll retrieve products from the JSON file defined earlier. Then, we'll loop through the product and render the product.html partial template.

As you can see, we also import a header.html, footer.html and product.html file. Let's take a detailed look at these. Before going further, we'll head to the layouts folder again and create a "partials". If partials file aren't put in this folder, Hugo won't be able to recognize them as partial templates and the {{ partial ... }} syntax won't work at all. The other important thing to know about this file is the dot "." after product.html. It means that you include the current product data in the product.html template.

layouts/partials/header.html

Like mentioned above, this file is the most important one. It's a simple HTML header file with Snipcart dependencies. Place it in the partials folder:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">  
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">

  <title> Snipcart integration in Hugo! </title>
  
  <link id="snipcart-theme" type="text/css" href="https://cdn.snipcart.com/themes/2.0/base/snipcart.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>

<body>
  <div class="container">
    <nav>
      <div class="nav-wrapper">
        <a href="#" class="brand-logo">Star Trek shop</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
          <li class="snipcart-summary">
            <a href="#" class="snipcart-checkout">
              View cart (<span class="snipcart-total-items">0</span>)
            </a>
          </li>
        </ul>
      </div>
    </nav>
  </div>

We decided to use the MaterializeCSS framework to style this static e-commerce demo, but you could use any other CSS framework. I found this one quite easy to integrate, and it provided enough built-in components to put together something that looks neat!

You'll also notice that Snipcart's required files are included in this template and that we added a cart summary to give customers a shortcut to their ongoing order.

So! Next step: putting together the footer partial template, to complete the core of our HTML file.

layouts/partials/footer.html
        <div class="container">
            <footer class="page-footer">
                <div class="footer-copyright">
                    <div class="container">
                        Snipcart integration with Hugo
                    </div>
                </div>
            </footer>
        </div>
        
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>

        <script type="text/javascript" id="snipcart" src="https://cdn.snipcart.com/scripts/2.0/snipcart.js" data-api-key="M2E5YjA3NjMtYzRiYS00YzVjLWEyYWYtNDY5ZDI0OWZhYjg5"></script>

        <script>
            Snipcart.execute('registerLocale', 'en', {
                powered_by:
                "HoS 'ej pong ngaQ "
            }); 
        </script>
    </body>
</html>

Finally, we need to generate the template displaying our Star Trek product details. Let's name the file product.html.

layouts/partials/product.html
<div class="col s6">
    <h2 class="header">{{ .name }}</h2>
    <div class="card horizontal">
        <div class="card-image">
        <img src="{{ .image }}">
        </div>
        <div class="card-stacked">
        <div class="card-content">
            <p>{{ .description }}</p>
        </div>
        <div class="card-action">
            <button
                class="snipcart-add-item waves-effect waves-light btn"
                data-item-id="{{ .id }}"
                data-item-name="{{ .name }}"
                data-item-price="{{ .price }}"
                data-item-url="{{ .url }}">
                    <i class="material-icons right">shopping_cart</i>
                    Add to cart
            </button>
        </div>
        </div>
    </div>
</div>

Since we passed the current product in our index.html template, we can now use every data fields in our JSON file. Here, I used them to populate my Snipcart buy button and add the product title + description.

Time to start our Hugo server and test that fancy website!

hugo server

(I'm saving my Star Trek shop screenshot for the end; brace yourselves)

4. Setting up Hugo deployment on Netlify

Last but not least: hosting the whole thing!

We decided to deploy our Hugo demo using the amazing service by our friends at Netlify.

Before doing anything in Netlify, I suggest creating a .gitkeep file in your content folder. This folder is required by Netlify's build bot. And as we did not lodge any files in this folder, Git is going to dismiss it.

Once the .gitkeep file is in place, you can use their interface to easily deploy your website in a few seconds. Here's a sneak-peek of our old school Star Trek shop deploy configuration:

hugo-website-deployment-netlify

Netlify will automatically pull your code on GitHub and deploy your website. And that's it.

hugo-tutorial-klingon

Live Hugo website example + GitHub repo

So, time to reveal our Star Trek masterpiece, folks:

static-ecommerce-shop-hugo-website-tutorial

Is your mind blown or what? Now go check both the site and the code out for yourself:

See live Snipcart + Hugo demo

See GitHub code repo

Conclusion & further resources

I think our job here is done, friends!

In case you're wondering if the end result is speedy enough, you can use another cool Netlify tool: Testmysite.io. We scored 87/100 with the demo; not too shabby.

BTW, if you're building a serious/client JAMstack site, you might want to consider monitoring its performance with this free open source tool. Also, tech-savvy teams might want to look into this publishing workflow with Hugo.

Clients

Think dealing with Markdown-driven static content files won't cut it for clients? Some cool tools can help edit and manage content on top of Hugo. We suggest throwing one of the following static CMS into the mix:

For further reading regarding JAMstack tools for clients, limits, & benefits, check out this comprehensive guide.

Playing with Hugo was a joy. Its documentation was on point, and its near-instantaneous speed made the engineer in me smile every time I re-built my site. Crafting this Snipcart + Hugo website tutorial took me around two hours. And that's including styling the site with MaterializeCSS and hosting it on Netlify.

It always delights me to see how good a match modern site generators are for our HTML/JS shopping cart. :)

Now stop reading this blog and go build something awesome.


Got any questions regarding this Snipcart + Hugo tutorial? Any other static site generators you'd like us to cover on the blog? Hit the comments for any questions, suggestions or casual Klingon talk. And if you enjoyed this post, take a second to share it on Twitter!

Suggested posts: