Journey to Blogging CI/CD: From Jekyll to Hugo

In the previous post, I talked about much of the reason I quit writing posts was because of the painful workflow surrounding the whole deployment process. To top it all off, when I finally tried to automate it, I found out that the Jekyll theme that I was using had used had many unpinned dependencies: rather than specifying the version of each library that should be retrieved, the author of the previous theme had chosen to simply request the latest version available at any given time. The effect of this choice was that my builds would not be reproducable since part of the source lived outside of version control. That part of the source could, and did, break when dependencies made breaking changes in newer versions of their libraries.

While my first thought had been that I could discover the correct versions and pin them myself, I ended up reviewing the static-site generator landscape to see if any of them more closely aligned to my needs. It turns out, there was a much better fit for me.

It only took a little research on to settle on Hugo. Hugo is a static site generator written in Go. It is much easier to install on a system, has first class Windows and Linux support, a large userbase, and no external dependencies.


Installing Hugo couldn’t have been easier: after navigating to the Hugo release page on GitHub, I simply needed to download and extract the archive for my local OS.

Creating a basic site

At this point, I should have been able to import from my existing Jekyll folder structure with nothing more than hugo import jekyll. However, that failed to successfully import any of the frontmatter. Frontmatter acts as the metadata about articles that informs the generator about details such as titles, dates, and tags. While losing the frontmatter was a bit of an inconvenience, it was a relatively quick process to readd by with a few regexes and a few manual corrections.


At this point, I was ready to see the how my site looked.

hugo server

Once this command had run, my generated site was available to view locally at http://localhost:1313. To my surprise, the site was quite minimalist; Hugo ships with no default theme, so the rendered page was completely empty. If I wanted to see the state of my site, I would need to choose and configure a theme. After looking through the various themes for Hugo, I settled on Hyde.

For the most part, I followed the directions provided with the theme. The one notable exception had to do with how the theme was cloned; while I could have cloned the repo as they had suggested, one of my over-arching goals was reproducible builds. For that, I needed all of my assets and dependencies to be checked in to Git. So, rather than cloning the repository, I forked it and then added a reference to my fork as a submodule of my site repo.

git submodule add themes/hyde-hugo-theme

By using a submodule, the exact location and exact commit I’m referencing are both checked in to the repo holding my site. This removes both chronological coupling and an unnecessary externally-managed dependency.

Having completed the instructions from the theme, I launched hugo server again. This time, I had content.


The next critical thing for me was that I wanted to make sure that permalinks from my old site continued to work on my new one. With that in mind, another update was needed to config.toml.

    post = "/articles/:year-:month/:slug"

A milestone

Finally, refreshing the local instance of hugo, my site showed up just as I would hope. A few images were missing here and there due to variances in macro syntax between Jekyll and Hugo, but those were minor issues that didn’t affect the overall structure of the site. It was certainly pleasing to see my site running locally, but there were still a number of personal requirements that I hadn’t yet met. Still, taking a moment to appreciate a milestone is important. With this, I was ready for the next step: I knew how to build the site myself, but now it was time to teach this trick to a computer.