There’s plenty to be said for stuff that just works, and the Hugo static site generator (SSG) is a perfect exemplar of that well-worn descriptor. When you’re building a new website for a client, Hugo should be one of the first tools you pull from your bag.
This is because Hugo, like many other SSGs, creates sites with all the winning elements of the Jamstack formula: top-of-the-line security over which your clients won’t have to fret, tremendous client-side performance that will enhance their SEO efforts, and minimal use of hosting resources which could otherwise cost them plenty.
But, compared to those other entrants in the growing list of SSGs, Hugo has a major ace up its sleeve. You see, the thing you hear most about Hugo is no exaggeration: Hugo really is the fastest way to generate a website. This SSG can easily churn out hundreds of web pages in under a second on each build. That titanic velocity is possible because Hugo itself is built with the Go language. And, since every content change on an SSG-built site generates a new build, even in development, both you and your client will find that single Hugo advantage a compelling one.
Better yet, Hugo’s a single, self-contained binary — an app, if you will. As a result, it’s possible that neither you nor your client will need to worry about constantly updating various software dependencies, contrary to what’s necessary when you use most other SSGs. All of Hugo’s dependencies are baked in from the get-go, as are a wide array of capabilities that require no plugins or add-ons.
That said, as with all website projects, it’s a good idea to set down a few guiding principles before you get started building a site with Hugo. So let’s discuss a few. What follows is not, nor do I pretend that it is, an exhaustive list. Rather, it’s a collection of tips that come to mind as a result of my personal experience with Hugo over the last few years.
Hugo is built from the ground up to make website content management easy, even surprisingly automatic. In fact, that’s one of the many reasons it’s such a great fit for CloudCannon. But, regardless of whether CloudCannon is in the mix for any Hugo project you’re doing, you can save much time and effort by knowing, and using as many as possible, of Hugo’s default settings and features. Here are just a few:
It’s important to know where Hugo expects to find things, so you’ll want to learn its lookup order pretty early. The good thing is that it’s quite logical and, thus, soon grasped: for example, content goes in
/content and layout templates go in
/layouts. It gets more extensive than that, but it won’t take you long to get a feel for it.
Speaking of the lookup order, Hugo’s built-in asset pipeline, Hugo Pipes, can process applicable items only if they’re in the asset directory for the project (or theme, about which more shortly). Of course, they can be in subdirectories within it. Let’s say your asset directory is the project’s top-level
/assets directory. If so, Hugo Pipes can work with the contents of, e.g.,
/assets/scss, and so on.
If your clients will be creating new content with the
hugo new command, a specific archetype template file will automatically provide a new content file with the minimally acceptable content, including front matter, saving the content creator from having to start totally from scratch each time.
It’s not a one-size-fits-all situation, either: you can set up different archetypes to conform to how and where the content will be created.
Although the site often can be just fine with only one set of layouts and styling, there can be various reasons to keep multiple such themes in a project. (For example, I have done so whenever I wanted to switch back and forth between two different CSS styling methods for testing purposes while otherwise keeping everything the same.) Hugo makes this easy.
Of course, building multiple themes obviously requires more work on your part — although you may be able to copy and paste much more than you think, especially where the underlying code “guts” are concerned. However, the actual switching between or among themes is as simple and quick as changing a one-line setting in the site-wide configuration file. Then, the aforementioned lookup order tells Hugo where to find the theme’s directories and files.
Oh, and while we’re on the subject of themes: you’ll be glad to know they also can help you deal with what may be Hugo’s proverbial elephant in the room. That’s our next topic.
Templating in Hugo is a mixture of HTML and the Go language, on which Hugo depends. If your chief coding experience is with languages besides Go, you’ll want a bit of ramp-up to start templating in Hugo. Fortunately, there’s an easy way to do that — and your client can even help you! Because there are so many available themes for Hugo, it’s likely you and your client will find a few that look and/or work at least somewhat like the targeted website layout and design you have in mind.
Pick as many such themes as you can, and dig into their code to see how others did what you’re considering. Then, back up your findings with what you can find in the extensive Hugo documentation and the Hugo Discourse forum. This is the process through which I learned — and continue to learn — Hugo. The same doubtless is true for many other Hugo users. (Of course, if by some chance you and your clients find an external theme that’s already perfect for the project except for a few no-brainer edits, you’re basically home free! Just don’t expect to get that lucky. It happens, but don’t bet on it.)
Remember, too, that Hugo has been around for nearly a decade and, thus, its workings have been thoroughly explored by many bloggers, Stack Overflow, and Reddit. It’s highly likely that a diligent search for how to do [x] in Hugo will reward you with an answer and a valuable jump on handling similar questions in the future.
= operator for both initializing a variable and assigning or re-assigning its value, Hugo uses Go’s
:= operator for only initializing a variable and limits
= to re-assigning the variable’s value. (The
*/}} below indicate Go-style commenting in Hugo, much as
*/ do in most other SSGs.)
Correct use of `:=` to initialize $variableOne:
$variableOne := 1
...and correct use of `=` to reassign its value:
$variableOne = 123
...**but** this use of `:=` is incorrect because you've **already** initialized $variableOne:
$variableOne := 456
...while this use of `=` is incorrect for **initializing** this **second** variable:
$variableTwo = 2
As I said, it seems trivial, but you’d be surprised by how much debugging you’ll spare yourself by knowing that one little thing before you start working with Hugo templating!
You might wonder how you can speed up your build time with Hugo. The main thing I can say on that front is: try to avoid slowing Hugo down. So, as you build a Hugo project, consider these examples of that approach.
When styling your templates, take advantage of Hugo’s built-in support for Sass. Since all valid CSS works in Sass, you can start with “vanilla” CSS and enable Sass’s capabilities as you learn about them. Sass is proven, feature-packed, and lovingly maintained. The stability and non-fussiness of a Hugo installation will be ably complemented by the solidity of Sass.
(By the way: when installing the Hugo binary, be aware that only its extended version supports Sass. I recommend always installing the extended version, regardless of your current styling choice, just in case you decide to go with Sass later on.)
Work out a strategy for how the site will have responsive images, so your clients’ visitors will have the best possible experience, regardless of their respective devices’ screen sizes or connectivity.
You’ll need to consider how many images are involved or will be involved over time. Although another built-in Hugo capability is image processing, and Hugo can do it remarkably quickly (of course), the processing of each additional image — and its various iterations as you perform responsive image handling — will lengthen each build. So run some tests, adding various Hugo image transformations on multiple images, to get a feel for any build-performance penalties that may gradually come into play.
Furthermore, with the images residing in the project repository, this eventually could run up against a remote repository’s file storage limits. Some have made Hugo work with Git’s Large File Storage functionality as at least a partial workaround, but large sites and growing asset libraries cause increasingly degraded performance during development, as well as longer build and deployment times.
In the end, you and your client may even wish to consider storing the site’s images on a separate image processing/delivery service and simply “call” the images through URLs provided by the service. In the coming weeks we’ll see CloudCannon introduce digital asset management (DAM) support — most services of this type offer free tiers, so you and your clients could experiment with this method without having to make any final choices.
If your clients don’t already have a web host in mind, make them aware of the difference between “traditional” hosts and the Jamstack-savvy hosts, the latter of which obviously are where you’d steer them for any SSG-based site.
A Jamstack-savvy host like CloudCannon links directly to a project’s remote repository and automatically rebuilds the project’s website every time there’s a push to the repo’s designated main branch. This ensures a smooth workflow for both your development efforts and the clients’ use of the site.
On each site rebuild, the host puts the resulting content out on the “edge” — namely, a global content delivery network (CDN) — helping to boost the visitors’ perceived experience with the site, regardless of where those folks may be. Not all CDNs are equal, mind you; some have very few worldwide points of presence (PoPs), which makes them less effective for some visitors.
Fortunately, a CloudCannon-based site lives on a roaring fast CDN with hundreds of worldwide PoPs, far more than nearly all of its rivals. That’s just one of the many key advantages of using CloudCannon with your SSG of choice.
Subscribe to Hugo’s “Releases” page on GitHub so you can keep up with Hugo updates. While many of these changes are only incremental and, thus, unlikely to merit your attention regarding an existing Hugo site, there sometimes will be a new feature which can be of great use to you and your clients. One such example was a December, 2021, release adding the ability to fetch remote resources so Hugo could process them just as if they were local to the project repository.
Earlier, we discussed the hosting of a Hugo-based site. That brings up
another way that “Releases” page will come in handy. At build time, each
host loads a default Hugo version, which almost certainly isn’t the same
version your project is using. Thus, you must set the desired version in a
host-level environment variable, usually with the key of
When setting the value for the variable, be sure to use the full version
number; e.g., make it
0.90.0 rather than just
0.90. To confirm the
correct version number, refer to the “Releases” page, since that’s the
source from which hosts pull the specified binary version.
Hugo powers websites ranging from the tiniest personal blogs to complex corporate and government sites. Its awesome speed makes the building and maintenance of all those sites easier and more pleasurable for developers and content owners alike. Hugo definitely merits consideration for your website projects, and its unique advantages can make you a hero with your clients, not only at site creation time but going forward — especially if you pair it with a collaborative CMS like CloudCannon. Be sure to check out the other Hugo-related articles here on the CloudCannon blog for more information of this type.
Give your content team full autonomy on your developer-approved tech stack with CloudCannon.
Jaimie McMahon · 3 Mar 2023
George Phillips · 8 Feb 2023
CloudCannon · 7 Feb 2023