How I Met Your Mother switched from to Vercel.

I wrote this using Obsidian because I am still working on config.yaml :)

My blog has come a long way, from a self-hosted WordPress instance to


To PaperMod: great, minimal-config theme! I knew nothing about Hugo but hey, all I need to change is a few variables.

To Vercel: nice free service! It works great, deploys automatically with minimal config, has HTTPS, and works with *gasps private repositories!

To Cloudflare Registrar: great interface! The other website I was looking at was PorkBun but Cloudflare’s is way superior.


How I found out about PaperMod:

Why Jamstack? Because it’s free on Netlify, Vercel and a couple of other places.

Fork PaperMod’s example site (it’s a branch, I used “Download ZIP”) and start editing config.yml. The branch uses an older name hugo-PaperMod so change that before building.


Somehow PaperMod uses a newer Hugo version than Vercel, so I had to set HUGO_VERSION to 0.97.3 in Vercel’s settings.

Vercel deploys on every pull. To delete the extras: get the Vercel CLI at npm install -g vercel and then vercel remove <project> --safe. The blog post where I found this also shows how to delete the annoying “Deployed” comments after every pull.

During config I found Lex Cao’s website and AimerNeige’s website which were helpful in figuring out some of the parameters, like setting a content directory for each language, which looks better than, say,


Even the free version of has an export page here.

The Hugo site lists 4 options as of right now; blog2md is the node.js solution that requires minimum config. It also ignores private posts!

One setback is that all underlines were escaped into \_, even in URLs. I had to do a flat search in VSCode to find these. VSCode was also helpful in finding image URLs to download (blog2md keeps the original URLs.)

Tables also converted to plain text; I copied from the original WordPress page and used a Markdown Table Generator.

Unfortunately blog2md (or it’s default config) ignores deletion lines, so I had to go through every page and manually add ~~.

I also tried wpxr-to-static, but it does requires some config on the export formats; use this if you have experience with Hugo.

Somehow defaultContentLanguageInSubdir: true breaks the 404 pages and (default language’s) search. Disabling this resolves the issue - although the files are physically in /zh/posts, the URL is still /posts.

The RFC 2822 timestamps somehow goes through a validation process, so 6 February would not work. Therefore, I had to replace all the timestamps with ISO-8601 ones manually. (Manually because writing up a script is probably slower.)