Before you start your blog, you have to perform a set of essential choices – topics you want to write about, domain name, and the way you’ll publish your content. I choose the self-hosted WordPress platform with a slightly customized theme that I found on the Internet.

After more than two years of blogging, I migrated all my content to Hugo. In this article, I would like to show you why I decided to move on from WordPress to Hugo – a static page generator.

Why I started with WordPress

Before I tell you why I changed WordPress to Hugo, let me explain why I choose WP as my leading platform.

When it comes to writing a blog, we have two definitions:

  1. Write a blog – write a whole blog engine from scratch.
  2. Write a blog – regularly publish new content to share knowledge.

If you want to start blogging and you begin with creating your own CMS, blogging platform, or something like that, you’re doing it wrong. You just create another piece of software, side-project, or something that you should maintain in time. I had tried this path, and it turned out that I wanted to test myself if I can write a blog engine rather than a blog itself.

Does it mean that creating a blog engine from scratch is bad? – No, if your goal is to create a blog engine.

When I started my current blog, I decided to focus on content. I wanted to write and publish regularly, and I knew that I don’t want to spend time maintaining a platform. I thought big, but I wanted to start small. I choose the safe option – WordPress with a free, easy to customize template. Easy to modify because it’s PHP. Easy to extend because of lots of plugins. It worked.

So the reason was simple – content is more important than platform.

Why I changed WordPress

WordPress needs PHP-powered server

My blog was simple. I hosted my articles with comments feed, and I needed some space for images and other assets. Besides that, I had a few pages with extra information, e.g., contact and about me. That’s it.

Since WordPress is written in PHP, it needs a server to operate. It’s not a high cost, but it’s still the cost I incurred. For me, it was no reason to pay money for it knowing that I can reflect the same functionality on a statically generated page an host it for free.

WordPress needs constant maintenance

WordPress is a living project. It gets frequent updates, as well as its plugins and themes. It happened that I had updated them a few times per week. It wasn’t necessary, but it’s better to keep everything up-to-date.

When it comes to the themes, I used a child theme that derivates from another template. It was a rare situation, but when I updated the parent template, something break on my page. It happened twice, but I’ve never been ready to put extra time to fix it.

WordPress is well-known for bots

WordPress is a very popular, open-source project which powers millions of websites. They serve the comments system, login form, and many other things in the same way. Bots that browse the Internet know how to scrape data, write comments, and how to attack login form with some default credentials.

Thanks to plugins like Akismet and Wordfence, which mitigated the effects of bots and potential attackers, my blog instance operated normally. However, my website is so simple that I don’t want to worry about security.

My WordPress-powered blog was slow

I didn’t take care of the speed site at the beginning of my blogging journey. If you have little content and no visitors, the speed is not a factor you should improve.

I’m interested in optimization, so I knew that plenty of things in my theme could be better. Instead of investing time to fix them, I set up Cloudflare as a proxy for my website. Thanks to it, it was caching most of the resources, increasing the overall site speed in the outcome.

The result of PageSpeed Insight for my old, WordPress powered blog. Score: 56 for mobile.
The result of PageSpeed Insight for my old, WordPress powered blog.

I didn’t test any cache-related plugin in WordPress, but maybe it could solve the problem with speed?

Why I moved to static page?

I heard about static-page generators way before I started my blog. I didn’t have any experience with them, but the whole idea was promising. During years, a lot of static page generators emerged, and more blogs were conducted this way.

I tested Gatsby for a while to check what it offers. However, I dropped out of it and picked the Hugo instead. I read a lot about how fast and simple it is. Unlike Gatsby, Hugo doesn’t provide any plugin system, so everything depends on the used theme. For some people, this is a huge limitation. For me, it was a nod to simplicity I like.

Ultimately, I migrated to Hugo because it fits perfectly in my workflow, whereas publishing with WordPress just limits me.

Code is a single source of truth

Hugo generates the page from files, so everything is reflected in the code base and versioned in a git repository. There is no external database providing additional configuration and admin panel, where you can change some settings. Code is a single source of truth.

If I want to change something in layout, I don’t have to look for a proper hook in WordPress lifecycle – I just go to the file and modify it. If I need to update CSS, I go to the stylesheet without thinking if Additional CSS in theme customization will be better for this change or not.

I’m a programmer, and working with the code is more convenient for me than jumping across the interface. It is also valid for my writings – I prefer to write using Markdown syntax, instead of formatting options in a rich-text editor.

One place for my writings

I used to store my writings in a separate repository to have a history of all changes. Because I published with WordPress, I had to convert articles to HTML and then put them to blog.

Writings are living things. Although I like to write timeless materials, sometimes I need to update them because my understanding of a given topic got better. Sometimes I just notice a language mistake I want to fix. Having the same content in two places was inconvenient, especially when I had to provide a change. I often forgot to move updates from WordPress to origin files.

Hugo supports Markdown. It works purely on text files, so all of my writings are in one place in one format. I can edit them using my favorite editor and publish them without worrying about how to move it to WordPress1.

Why I migrated to Hugo?

The features I mentioned above are not exclusively in Hugo but almost in every other static page generator. However, Hugo met all my criteria: is fast and straightforward, has content powered by Markdown, its engine isn’t in JavaScript. The last one is related to the problem of longevity. I want to have something reliable for years. I don’t want to be surprised that I can’t generate my blog because of issues with dependencies after an update. The second reason was more prosaic – I want to try something new.

Migration

The whole migration process took me more time than I expected, but I should consider it as a normal situation – estimation is a hard thing. The migration process had three main parts: template migration, content migration, and deployment.

Template migration

Previously my blog was powered by a customized version of template called Themelia. It’s a simple theme, and I wanted to keep the same simplicity.

My blog on customized Themelia template.
My blog on customized Themelia template.

I had been looking for the template for Hugo, and I found the project hello-friend. It’s a blog template with a clean design, very similar to what I needed. I decided to use it as a foundation for my custom theme. Its author, Radek Kozieł (@panr), has done an outstanding job – Thank you, Radek!

After a few modifications, the blog started looking similar to the WordPress version.

Content migration

Although I kept drafts of my posts in Markdown, most of them were not updated with the live version. To avoid publishing old content, I decided to migrate everything from WordPress.

In the beginning, I tried to do everything manually, since I didn’t publish lots of articles. I was coping and pasting the content from WordPress and manually changing HTML tags to Markdown and tweaking YAML Front Matter. After three posts (or a few hours), I thought that it had to be an easier way to do this.

I had installed WordPress to Hugo Exporter plugin, and thanks to it, I saved a lot of time. It did 90% of the work I had previously done manually. Great tool.

In exported articles, I had to change yet:

  • YAML Front Matter and settings related to the used Hugo theme
  • Hardcoded internal links to links generated by ref Hugo’s function
  • Display images by figure shortcode, instead of Markdown syntax (to have a caption built-in)

YAML Front Matter

My YAML Front Matter looks as follows:

---
title: Why should you return early?
date: 2017-11-20T09:00:25+00:00
slug: why-should-you-return-early
cover: images/Featured-Return-early.jpg
useRelativeCover: true
categories: 
 - Software Development
tags: 
 - Code Style
 - PHP
 - Software Design
---

The migration tool put the url parameter for each post. However, I prefer to use a slug instead. Properties cover and useRelativeCover are used by the template to display the post’s featured image.

Content organization

Group articles together

The migration of the content was the one problem, but how to organize them in Hugo is a different story. By default, Hugo reflects the structure of the content directory during page build. However, links to my articles consist of domain and slug – they are in the “root directory”.

I’d not like to keep everything in one single directory. Fortunately, Hugo allows configuring permalinks to the specific type of content.

So, i put all of my posts to /content/posts directory and in config.toml I configured a proper permalink:

[permalinks]
  posts = ":slug/"

Content ordering

Most of the IDEs keep file structure ordered alphabetically. When it comes to my writings, It’s more comfortable for me to order articles by published date.

I prefixed each article with the date to retain the order. Without it, old content was mixed with the new one, and everything looked messy. The one downside is that I have to override the slug property in YAML Front Matter for each post. Otherwise, the URL will contain a date as well.

Store assets using Page Bundles

Page Bundles in Hugo allowed me to keep together everything related to the single article. It means that I don’t have to put every image in static directory, which was default place for pictures and other non-processed stuff. Moreover, images stored as page resources could be processed (resize, crop, transformation), so it’s a way for future optimizations.

So, instead of keeping markdown files directly in the content/posts directory, I created a separate directory for each article and other related assets.

Comments

Comments were the big unknown for me since that was the only dynamic part on my website. However, I realized that most of the comments I got were spam filtered by Akismet. Besides that, I got a few valuable comments, which were a big inspiration for me – thank you.

I read a lot about the Disqus, and I saw the pros and cons, but I don’t want to bloat my site with ads, trackers, and so on2. I would set up my own comments system, but this is another piece of software I would have to maintain, but you know – self-hosted services, although free, have a hidden cost.

I explored the Indieweb and found feature called Webmentions. It looks promising because it would let me collecting mentions about the post from external channels, like e.g., Twitter. Yet, this way of commenting is not obvious for everyone, and I would treat it more like an extra rather than a default manner.

So, for now, I don’t have comments. Maybe I’ll add them in the future. If you want to refer to my article, the best option to do it for know is Twitter – you can reach me out there by mentioning @skrajewski.

Hosting and deployment

Since I move to the static page, I don’t think I need the whole LAMP stack any longer. I paid for the hosting (not so much, but this investment was not paying back), but for now, it would be overkill.

I did a little research, and it turned out that lots of services offer free (but limited) hosting of static pages. I thought about the GitHub pages, but eventually, I landed on Netlify, mostly because they provide CI solution for Hugo websites. Moreover, Netlify manages its CDN, so it’s no need to use services like Cloudflare. It’s can also generate and renew SSL certificates using LetsEncrypt.

What is also important, Netlify handles redirects, so providing a custom 404 template or redirect from old article URL is not a problem.

What I forgot or didn’t realize

I prepared myself for most of the situations, but there are some I wish to know about it earlier. Not big deals, but worth considering.

E-mail hosting

On my old hosting, besides the HTTP server, I took advantage of e-mail hosting. Once I dropped out of it, I lost e-mails addresses in my domain. I haven’t used them so much. However, for me, they were a nice addition.

I’ve looked for e-mail providers, but I can’t find any affordable solution. It’s not crucial for me. Therefore I don’t want to spend too much money on things I don’t urgently need – otherwise, I probably would stay on previous my hosting. If you know worth recommended e-mail hosting providers, please let me know on Twitter.

Markdown is less Markdown

Markdown is simple. If you need to write text with headings, some tables, and images – it’s a perfect choice. However, the more custom features you want to implement in your articles, the less Markdown it becomes.

In Hugo, if you need to display something custom in the article, you need to use a shortcode. The one shortcode may display a responsive image, other an alert, or an infobox. But in any other Markdown editor, they have no representation, and they are just text. Moreover, ugly text.

{< figure src="057_window_keyboard_shortcuts_help.jpg" alt="The Keyboard Settings Window on macOS with the enabled shortcut on the list." caption="Keyboard Settings Window. Make sure you have \"Show Help menu\" action enabled and assigned to the proper shortcut.">}

If you want to keep your articles in Markdown, you’ll need to limit the number of shortcodes you use. Hugo allows to set up Markdown render hooks, so you can provide templates for images and link that Hugo3 uses during parsing native Markdown syntax.

Summary

The whole process was fun, and I learned a lot by migrating from WordPress to Hugo. It’s still a lot of things to do and ideas to implement and test, but it’s not crucial at this moment – the more valuable is content – articles that I produce, and you read.

Do I regret that I started with WordPress? No. Using WordPress as a platform is convenient, and if your goal is to write, you don’t need anymore. I didn’t worry about the technical details, images, and so on – everything was managed by the blog engine.

But WordPress allowed me to meet my needs. I saw that some things are not for me, others are fantastic and some others could be better. I decided on migration based on the experience, not the hype. WordPress is still a choice for people with no technical background.

Remember that the essential part of each blog is the content it serves. Not template, not an engine, but the author’s effort to assemble thoughts in writing.

I hope you’ll find value in this article.


Featured photo by Webaroo on Unsplash.


  1. I heard about the JetPack plugin that brings Markdown support to WordPress. However, it’s not kind of plugin I wanted to use anyway. ↩︎

  2. You can find more details about the Disqus privacy and performance concerns in Marco Saric’s article or Victor Zhou’s artcile, or by looking for phrase “Why should you remove Disqus”. ↩︎

  3. Hugo uses Goldmark renderer, which supports this kind of hooks. ↩︎