WordPress to Hugo Blog Migration

After many years of underuse, I finally got around to spending some time updating this site. I originally set it up on WordPress many years ago (2005-ish), and then mostly ignored the WordPress part, really only updating it when forced to via some security issue. This is exactly the opposite of what a software developer like me wants their users to do. When I’m building software, my general philosophy is that simple is better, and frankly, the complex ecosystem that is WordPress, its database, plugins and themes is far from simple.

For me, the ideal blog platform is something I can setup and not worry about, which brings me to the world of static site generators. I’ve been thinking of doing this for a while, but I have to admit I was finally motivated by my site actually breaking. Some automatic security update my hosting system (Plesk) applied was incompatible with something, and was generating 500 errors for a while. Though I got it ‘working’ again, I had to disable a bunch of things and change to a different theme.

Static Site Generators vs Database-driven CMS

One of the main things I want to avoid is the ability for a site to ‘just break’ like my WordPress site did. At the same time, I’ve long since disabled comments and so there’s really not any benefit to having a database-driven CMS anymore. In fact, the benefits of having all the content in a git repository are immensely better.

  • Content is all stored in git – which means version control and distributed
  • It’s possible to generate (and test) the output on my PC
  • It’s possible to deploy staging and alternative versions from different branches, without affecting the production version
  • The only software invovled is during the build process, there’s no backend that requires security updates

I’ve built and managed a handful of WordPress sites over the years (aside from my personal blog) and each time, one of the pains was making major changes. Usually it involved making a clone of the site + database, then moving that over to production when ready. In the worst case, you’d have to merge/migrate production content generated after the clone to the new database, which was always painful.

Generator: Hugo

I looked at Jekyl, Gatsby, and VuePress but I ultimately decided to use Hugo. It is a single executable that is stupidly easy to install and run, was pretty easy to learn, and has a large enough ecosystem of themes, supported platforms, etc.

One of the nice things is ultimately, it doesn’t actually matter too much what you choose for the generator part, as all the really matters is the output. They all store content in Markdown files.

I started with the Vienna theme (by Keichi Takahashi), and initially used override files to make a few tweaks. By the time I was done, there were only a couple files I hadn’t overridden, so I’m just using my own custom theme at this point.

Content Migration

I used the wordpress-to-hugo-exporter plugin to get the bulk of the content over. This mostly worked, but I had to do a few extra things:

  • Fixed many internal URL links (regex replace) that were using the FQDN. Aside from the fact I moved to a new domain, this made the links not work locally.
  • Fixed almost all image links, as well as put the old images into their own directory (this is basically the old wp-content folder)
  • Converted the “Categories” to “Tags” (regex replace)
  • I had to tweak several post URLs, mostly from old posts, and add aliases for the old locations

I also added redirects on my old site, using .htaccess, which will preserve existing URLs:

RewriteRule ^/blog(/.*)$ https://blog.gregmac.dev$1 [R=301,L]

Source: GitLab

The source is stored in a private GitLab repository. Why private? This lets me have drafts that aren’t publicly visible.

Hosting: Netlify

Deployment status: Netlify Status

Hosting on Netlify was pretty simple. Once I pointed DNS for my domain there, SSL was automatically configured within a few minutes. The only gotcha I ran into was it was using an older version of Hugo (0.53 I think?) and giving me some parsing errors, but this was fixed by a minial netlify.toml file to tell it to use the newer version:

publish = "public"
command = "hugo --gc --minify"

HUGO_VERSION = "0.57.2"
HUGO_ENV = "production"

Despite having a web host for my old domain (and a bunch of others) I decided to use Netlify mostly because of the automatic wire-up of the build process. Doing it on my own host would have meant configuring a build pipeline and setting it up to transfer files to my host (and worring about securing credentials for that) – which is pretty easy, but is still something else to maintain. If there’s one thing I’ve learned from neglecting my old blog for a few years it’s that I don’t want to maintain more stuff.


If you’re currently on WordPress (and only begrudingly update it) or are considering starting a new blog or simple site like this, I highly recommend going with a static site generator if you can.