Migrating from Hyde to Hugo

Posted . #general #coding

Almost twelve years after the last big site infrastructure change, it’s time for another round. This time is purely technical, with no intentional visual changes.

Motivation

I haven’t posted in a long time, and this blog had largely faded into the background for me. I was doing some management of my domains, trying to clean things up after my domains registered with Google were transferred to Squarespace. As part of this, I decided to use Cloudfare as my nameserver, which I’ve used for other projects.

I started reading about Cloudfare Pages, which seemed like a great match for easily deploying a statically-generated site. You can point Cloudflare to a GitHub repo, and it will automatically kick off a build after every commit, and deploy the static artifacts. Unfortunately, the Hyde framework I was using is no longer maintained, and still does not support Python 3. Cloudflare Pages does not have support for Python 2.7.

So I decided it would be a fun project to migrate to a new static site generator.

Finding a new tool

Searching around, I quickly settled on Hugo due to its large community, and reputation for blazing fast speed.

I wasn’t quite sure how the easy it would be to migrate my old site template, so I started off following the quick start guide, chose an existing public theme that looked ok, and started copying the content from my site’s old repository. This was pretty easy since both tools are based on Markdown – I just needed to slightly adjust each post’s metadata. With less than 20 total posts, I did that manually.

Fundamental differences

Hyde is a very simple generation tool, compared to Hugo which has a much larger feature set, but also very strong opinions on how things should be structured. In Hyde, I had a flat folder of templates, and could directly point individual pages to an arbitraty template.

Hugo has a very specific structure to follow, which it leverages to classify into a set of page types. This prevents the organizational structure that I wished to have, but I quickly adjusted. For example, my previous file hierachy looked like this:

content/
content/blog
content/blog/2025
content/blog/2025/01
content/blog/2025/01/post.md

Having multiple nested directories is not easily supported, so I needed to switch to the following hierarchy:

content/
content/blog
content/blog/2025-01-post.md

Given the limited number of posts, I don’t mind this setup too much. However, if I were a more prolific blogger, I would probably dig in to find a better way to organize individual post files.

Porting a Hyde theme

Hugo themes are also much more structured than the ad-hoc Hyde layouts. There is a rigid template lookup order, which required some trial-and-error to determine where all of the template types needed to live in order to get picked up correctly.

Hugo uses a Go templating library, so I needed to tweak all of my previous Jinja2 templates. This was a bit of manual work, but overall not too bad, largely because of the rich documentation available.

On the plus side, Hugo does have built-in templates for Google Analytics and Disqus, both of which are used on this site. Rather than needing to include the code for those in my templates, I could just define some simple config parameters and reference the built-in templates:

<head>
  {{ template "_internal/google_analytics.html" . }}
</head>

For posts, I ended up defining one “single” template, which is used for both posts and standalone pages like About. I need conditional logic to prevent showing Disqus on non-posts. I settled on excluding pages that appear in the site navigation menu:

{{ if not .Params.menu }}
{{ template "_internal/disqus.html" . }}
{{ end }}

Final result

As before, the code for this site remains open source. I left the old code in its own repository, and created a new repository for the Hugo-base site implementation, which you can find on GitHub.

comments powered by Disqus