Background
I’ve hosted my blog on a lot of different platforms over the years, WordPress, Ghost (self hosted and cloud), Jekyll via GitHub Pages, and probably some I’m forgetting. The paid solutions like WordPress and Ghost were nice and simple, but being a developer I like to maintain and tweak things, and eventually the cost also became an issue for my low-traffic personal blog. When I discovered GitHub Pages a few years ago, it seemed like the perfect solution for me. Low maintenance, simple, and best of all, free! I decided to go with Jekyll for some reason, and the initial setup, choosing a theme, etc. was easy enough.
Then came the problem. I don’t update my blog particularly often, sometimes leaving it for years at a time. Inevitably, whenever I did want to write something, I first wanted to make sure it was using the latest version of the theme I’d chosen, and Jekyll. This led to many hours of pain, fighting with Ruby versions, and trying to find a configuration which satisfied all components. Then things got worse… 😬
Recently I tried Cloudflare Pages for another blog, and loved it. I wanted to have this blog published over on Cloudflare, and then eventually move it off of GitHub Pages and repoint my domain to Cloudflare. This was even more of a headache, and after a few hours of trying I eventually gave up and decided to try something new ✨
Enter Hugo
I’d heard about Hugo years ago, so I did a bit of research and decided to give it a try. I’m much more familiar with Go than Ruby, so it seemed like a good fit, and Cloudflare natively supported it for their Pages service. Also, it seemed like I’d be able to import my Jekyll posts into it with little to no modification. I did a bit of research and decided to use the PaperMod theme, as it suited my needs and my taste.
I followed the official guide on Cloudflare (linked below), and referenced a few other online blog posts to confirm the details. It was easy enough to set up, create the repository, configure Cloudflare Pages, and so on. Of course, it didn’t work! The Cloudflare build failed 😪
The Problems
The build failed at first because Cloudflare couldn’t find PaperMod. After a bit of trial and error and recreating the Git submodule for the theme, it worked!
Now it failed on a different error, progress! 🎉 It seemed like PaperMod didn’t support the version of Hugo that Cloudflare was using to build the site. A bit of searching led me to a very helpful blog post which explained that, by default, Cloudflare uses a very old version of Hugo. I looked up the latest version of Hugo, the same one that I was using locally, set it in the build config, and retried the deployment… Of course, it failed again! But this time with a different error 💡
This time, it had issues building the various parts of the theme, to do with templating. The logs indicated something interesting. Since version 0.146.0 they’d changed how something was interpreted, and it was warning that it had detected matching elements, and that the behaviour may not be as expected. Armed with this information, I adjusted the config to set the version of Hugo to 0.145.0, the latest one before 0.146.0.
In the end, after a few hours of troubleshooting, it worked! 🎉
Summary
What should have been a quick migration ended up taking multiple hours. Once again, the dependency hell that’s ubiquitous to static site generators caught me out. At the time, this particular Hugo + PaperMod + Cloudflare Pages combination was much more awkward than I expected. Below I’ve included a summary of the steps I took to create the blog, migrate my old posts, and set it up on Cloudflare.
Update (March 10, 2026): This post is still an accurate account of my migration experience, but parts of the deployment guidance below are now historical. Cloudflare’s current Hugo guide recommends using
hugo -b $CF_PAGES_URLwhen you want correct absolute URLs on Pages, and settingHUGO_VERSIONin the Pages project environment variables if you need to pin a specific Hugo version. Separately, this repo currently builds locally with Hugo0.157.0, so treat my older0.145.0workaround as a point-in-time fix rather than current default advice.
Instructions
The official instructions from Cloudflare on how to deploy a Hugo site are pretty good, I mostly follow them, supplemented by the excellent post on ryomayama.com, How to Deploy a Hugo (PaperMod) Site to Cloudflare Pages, which covers PaperMod specifically. I’ve added a few of my own comments and caveats.
1. Hugo Setup
Install Hugo:
brew install hugo
Create your new site:
hugo new site <your hugo site> --format yaml
Note: By default Hugo will use the toml format. This is old and annoying to work with, so just tell Hugo to use yaml to make your life easier.
Initialise your Git repo:
cd <your hugo site>
git init
Add the PaperMod submodule:
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
Set Hugo to use PaperMod, and create a .gitignore file to exclude the public directory. This directory is where Hugo puts the files it generates, and doesn’t need to be committed to the repo.
echo 'theme: ["PaperMod"]' >> hugo.yaml
echo "public/" >> .gitignore
2. Create a test post
Create your first post, so that you can run Hugo locally and make sure everything works.
hugo new posts/hello-world.md
Open up hello-world.md and add whatever content you’d like to it. Note, it’ll be generated with draft: true, but for it to show up on your site you’ll need to either delete this line, or change true to false.
3. Run Hugo to make sure it works
Simply run:
hugo server
The command should succeed and run the Hugo development server. If it works, it should output a link that you can visit in your browser, something like http://localhost:1313/. Open the link and make sure the site loads, and that you can view your first post. Try the Hugo Troubleshooting page if it doesn’t succeed.
4. Customising your site
Open up hugo.yaml and you’ll see a few things you can edit which are self-explanatory, such as baseURL and title. Update these as you see fit.
There are many more useful options you can include in this file, some examples below. Many of these can be included in your post specific options to override a certain one if you need.
params:
keywords: [Blog, Tech] # Specify keywords for your blog, for SEO
author: Yestin # Set the default author of your posts
defaultTheme: dark # Set the default theme colour
ShowReadingTime: true # Show the reading time on posts
ShowShareButtons: true # Show share buttons on posts
ShowPostNavLinks: true # Show nav links on posts
ShowBreadCrumbs: true # Show breadcrumbs on posts
ShowCodeCopyButtons: true # Show the copy button for code snippets
ShowWordCount: true # Show the word count on your posts
showtoc: true # Show the table of contents on your posts
hideSummary: true # To hide post summary on the home page
# Display content on your blogs home page, above the list of posts
homeInfoParams:
Title: "Hi there"
Content: Welcome to my awesome blog.
# Define some social icons to show below this content
socialIcons:
- name: email
url: 'mailto:me@example.com'
- name: github
url: "https://github.com/<your_github_username>"
For the full list of the social media icons you can use, see Icons.
# Define a menu to be displayed on the top right
menu:
main:
- identifier: home
name: Home
url: /
weight: 10
- identifier: categories
name: Categories
url: /categories/
weight: 20
- identifier: tags
name: Tags
url: /tags/
weight: 30
For each post, you can also specify options. One I’ve found useful is:
summary: 'blah'
This lets you specify the summary of the post, to be displayed under the post’s title on the home page.
For a complete reference see the Hugo documentation or the PaperMod Features/Mods page.
Make sure you re-run hugo server, or if it’s still running it should auto reload. Check that your blog is as you want it before continuing.
5. Commit your changes and push them to GitHub
Stage all files in your repo and commit them.
git add .
git commit -m "Initial commit"
Push your changes up to GitHub. You’ll have to have a corresponding repo there already.
git remote add origin https://github.com/<your-gh-username>/<repository-name>
git push -u origin main
Check your repo on GitHub to make sure it pushed correctly.
6. Setting up Cloudflare Pages
The final step is to create a new Cloudflare Pages config for your Hugo repo.
Follow the official instructions from Cloudflare here.
Back when I first set this up, I ignored the section on “Base URL configuration”, as it didn’t seem necessary for my setup. Cloudflare’s current guide now recommends using hugo -b $CF_PAGES_URL if you want correct absolute URLs on Pages.
At the time I wrote this, pinning Hugo was necessary to get this particular setup working. Cloudflare’s current guidance is to set the HUGO_VERSION environment variable in the Pages project settings whenever you need to pin or upgrade Hugo.
At the time, I ended up using 0.145.0, because that was the newest version I could get working with this repo and theme combination. As of March 10, 2026, this repo also builds locally with Hugo 0.157.0, so treat 0.145.0 as historical context rather than current recommendation.
7. Migrate your Old Posts
If you have old posts from Jekyll or another markdown based blogging platform, you can easily import them into Hugo by simply copying them into the correct directory.
For Jekyll, I ran the following command:
cp -r /path/to/jekyll/repo/_posts/ /path/to/hugo/repo/content/posts
They shouldn’t require much modification. I did end up enclosing strings in the options at the top of the posts within single quotation marks. For example:
---
title: My blog post title
date: 2022-06-25T10:32:34.000Z
categories: [Sample]
tags: [test]
---
Became:
---
title: 'My blog post title'
date: '2022-06-25T10:32:34.000Z'
categories: ['Sample']
tags: ['test']
---
Conclusion
Thanks for reading. I hope you found this useful, and that you have an easier time setting up your new Hugo site than I did 🤞
Acknowledgements
Ryoma’s post, How to Deploy a Hugo (PaperMod) Site to Cloudflare Pages, was extremely helpful and in particular mentions specifying the Hugo version in the build config, which I missed at first 🤦♂️ It was almost exactly what I needed.