Will's avatar

⬅️ See more posts

Re-Building my Website with Hugo

3 September 2022 (6 minute read)

🔮 This post is also available via Gemini.

technology javascript

Pixel art of people coding.


For several years I’ve been using GatsbyJS to generate the static site content for this website. Gatsby is a great tool and produces blazing-fast websites through the use of an interesting combination of technologies.

In Gatsby, pages are simply React components, and developers can make use of the entire JavaScript and React ecosystems to craft their sites. Config files can be used to create pages that don’t “exist” in your filesystem (e.g. an index page for each tag used in a blog) and GraphQL queries are used to surface content and query data from across the website. Gatsby templates and standard React composition patterns allow for excellent re-use of components.

When building the site, Gatsby produces standard HTML files for each of your pages, such that they can (in a limited sense) be accessed by JavaScript-less browsers. When JavaScript is enabled on the browser, Gatsby pre-fetches content automatically in the background and routes requests internally to make navigating through the pages extremely quick.

Gatsby has served me well for a number of years and I’ve written a number of posts on this blog around tweaking and enhancing setups to give even better experiences.

Why consider a move?

For a small personal website, like mine, however, Gatsby felt a bit overkill. I shouldn’t need to write JavaScript to present simple static content, and dealing with the JS dependency graph and a huge default node_modules/ is a little like hitting a nail with a sledgehammer.

When updating Gatsby or any other dependencies, I’d always end up fighting against issues with incompatibilities, taking my time away from actually producing any content. GitHub’s Dependabot alerts would email me frequently about insecure packages somewhere in the graph, which I wouldn’t mind so much if I wasn’t simply needing just a small bunch of HTML files.

I find the Gatsby config files hard to understand, read, and write. I’d often end up blindly copying bits from other examples without really understanding what they were doing. The same applies to the GraphQL queries; I never really got my head around these in the Gatsby context, and I ended up reducing the site’s functionality because I couldn’t achieve what I wanted to. Sure - I could spend more time learning about these concepts but I just couldn’t bring myself to do so when my target needs of the system are so simplistic.

As the site got bigger I found that the build times also increased. Towards the end of my usage, the site would take 20-30 seconds to boot the hot-reloading develop mode, and building the production-ready site would often take a good minute or more. I use Vercel to host the site, and so I imagine it has to run a yarn install each time it builds too.

When in production, the site’s assets - whilst not huge - would be pretty sizeable given the actual content being displayed. Visitors shouldn’t need to load a React runtime just to view the homepage (though I do understand that the JavaScript components are there to improve the quality of the UX).

All in all, I felt that Gatsby was too big/heavy/complex for my needs, and with too many overheads in terms of up-keep and maintenance.

Switching to Hugo

Hugo has been on my radar for some time now, but I never got around to giving it a go. I understood its aims and characteristics (especially given my past experience with Jekyll), and it always seemed as though it would be a good fit for my needs.

Given my growing concerns about Gatsby, and having a couple of days of work downtime last month, I thought I’d give Hugo a proper try by attempting to port my personal website over to it.

I began by installing the hugo tool and creating a new site according to the documentation. I knew that Hugo content is mostly written in markdown, and since my blog posts and notes were already in markdown from their Gatsby days anyway, I could copy them straight over into the relevant directories under content/ in the new Hugo site.

Although there was now content in the site, Hugo would still render blank pages. This is because I didn’t have a theme configured. I had a quick look through the available themes on the website, but none of them really took my fancy. Instead, I started to build out my own basic theme by creating HTML files in the layouts/ directory.

My goal was to try and replicate my existing site as much as possible. Partly because this would be quicker (I wouldn’t need to come up with new designs and layouts), but also because I like its simplicity.

I gradually migrated all of my content over, making use of content organisation, indexes, layout files, and simple styling. The documentation is easy to follow and very intuitive. There’s no GraphQL to learn - it’s all just basic HTML, markdown and some simple Hugo functions.

Before long, I had the whole site copied over and built, and I also thoroughly enjoyed the process. I use none of my own JavaScript (aside from a couple of pieces I include, for which I’ll justify below), and so everything feels much simpler and cleaner. I now look forward to adding more content and continuing to tweak the site going forward.

Things I love ❤️

Here are some of the things I’ve found to love about Hugo:

  • Partials - like React components, these are great for re-using layouts and markup across a website.
  • Pipes - I use these for processing and minimising SCSS, and also for resizing and manipulating images.
  • Configuration - Super simple, from a single file. Changes automatically get reflected in the site when hot-reloading.
  • Speed - Dev environment boots in milliseconds, and the whole production site builds in <500ms.
  • Simplicity - No dependencies, other than the Hugo binary itself.
  • Content-focused - Super quick and easy to add new content, rebuild, and deploy.

The minimal styles, plus the fact that I use generally-available system fonts and scaled images (thanks to Hugo pipes) mean that the total size of the homepage, when downloaded and uncompressed, is less than 20kB.

This means that the site is now a Green Team member of the 512KB Club, and most of its pages are also measured to result in the production of extremely low CO2 per visit. Some included JavaScript on the page re-measures every now and again to keep this up-to-date.

I look forward to building more with Hugo and the community, and perhaps working on and releasing a theme sometime.

✉️ You can reply to this post via email.

📲 Subscribe to updates

If you would like to read more posts like this, then you can subscribe via RSS.