Hugo is a static site generator shipped as a single binary compiled in Go: to run the build you need neither an interpreter nor a package manager on the machine. The current version, as I write, is 0.9.0, released by Steve Francia on 15 November 2013. The project sits on GitHub as spf13/hugo, under an Apache 2.0 licence.
Context
Static generators solve a narrow problem: produce the HTML once, for content that changes rarely, and drop the application layer at runtime. Jekyll (2008) is the reference choice, partly because GitHub Pages runs it server-side: you write Markdown, apply Liquid templates, and the output is HTML any web server knows how to serve. The price is the Ruby environment โ ruby, bundler, gems with their versions โ and build times that grow visibly as the pages add up.
The two go together. The Ruby toolchain has to be installed and kept aligned between the development machine and the one that publishes; and on a site of a few thousand pages a full rebuild is not instant. Hugo goes after both points starting from the language: Go compiles to a self-contained executable, and the standard library already offers template parsing and concurrent handling.
Architecture
What you download is one file. On Linux, macOS or Windows you grab the binary for your platform and put it on the PATH; there is nothing to install around it. A Hugo site is a folder convention: content/ for Markdown content, layouts/ for templates, static/ for assets copied verbatim, config (in TOML, YAML or JSON) for the global settings.
Each Markdown file carries a front matter at the top โ a metadata block โ which Hugo accepts in TOML, YAML or JSON. The body is converted to HTML by Blackfriday, the Go Markdown implementation the project uses. Templates run on html/template from Goโs standard library, which escapes according to context; beyond the Go syntax, 0.9.0 also accepts templates written in Amber.
Content is organised through indexes: this is how Hugo builds groupings such as tags or categories from the values declared in front matter, and generates their list pages. The command has a sub-command interface modelled on git; hugo server starts a local server that watches the files and does LiveReload, so once the build finishes the browser updates without your having to reload it.
Critical point
The difference you actually measure is build time, and it comes from two choices stacked together: the compiled language and the absence of an interpreter start-up on each invocation. For the same content, a rebuild that an interpreted toolchain takes tens of seconds or minutes to run closes, on Hugo, in a fraction of a second. The exact figure depends on the machine and the site, so it should be measured case by case with a time hugo on your own project rather than inferred from someone elseโs benchmark.
More than the stopwatch, what counts is the consequence on the workflow. When the build is near-instant, watching the files plus LiveReload make the preview continuous: you save a Markdown file and the page in the browser is already updated. It is a tight feedback loop, close to that of an application with hot reload, yet the output stays static HTML, with no process listening in production.
Then there is distribution. The single binary simplifies reproducibility: the same version of hugo produces the same output in development and in build, with no dependency graph to freeze in a lockfile. The mirror-image drawback is that the Markdown engine and the template functions are the ones compiled into that binary โ to change them you upgrade Hugo, you do not swap out a gem.
Implications
The operating pattern is easy to automate: the source lives in a Git repository, a machine with the Hugo binary runs the build, and the HTML it produces is copied to a web server or to static hosting. The production server needs no application runtime, and the exposed surface is that of static files, with no dynamic layer to patch for security reasons.
For anyone coming from Jekyll the template switch has a cost: you move from Liquid to the html/template syntax, which has its own rules on functions, pipelines and data context. The mental model of content โ Markdown plus front matter, groupings derived from metadata โ stays recognisable, but the layouts have to be rewritten. For a new site that cost is not there; for a migration it has to be budgeted.
Limits
Hugo at 0.9.0 is a young project, a little over two years of history and a version number that says so. The pool of themes and documentation is far smaller than the one Jekyll has accumulated since 2008, and several conventions still move from one release to the next. Adopting now means committing to follow the release notes: I have seen names and behaviours change between nearby versions, and some third-party documentation points to settings already relocated.
Out of scope are sites that ask for runtime logic โ authentication, per-user content, server-side writes: there a static generator is the wrong tool regardless of language. Hugo is at its best when the content is mostly read-only and changes through successive publications: blogs, documentation, project pages. For everything else, the saving on build time does not repay the missing dynamic layer.
- https://github.com/spf13/hugo
- https://gohugo.io/
- https://spf13.com/project/hugo/
- https://github.com/russross/blackfriday
- https://golang.org/pkg/html/template/
- https://jekyllrb.com/
- https://www.noze.it/en/insights/hugo-static-site/
Cover image: The official Go programming language mascot, the light-blue gopher drawn by Renee French, in a high-resolution color version โ illustration by Renee French, CC BY 3.0 โ https://commons.wikimedia.org/wiki/File:Gogophercolor.png