The Night WordPress Died (In My Heart)
Picture this: It’s 3 AM. I’m on my fourth cup of coffee, staring at yet another “Critical Security Update Required” notification from WordPress. My shared hosting is screaming because some bot farm decided my xmlrpc.php was their new favorite toy. The monthly hosting bill? Let’s just say it costs more than my Netflix, Spotify, and gym membership combined (okay, I don’t have a gym membership, but you get the point).
That’s when I asked myself the question that changed everything: “Why the hell am I running a database for a blog that updates twice a month?”
Spoiler alert: There was no good answer. So I burned it all down and rebuilt with Hugo. Here’s how you can too.
Meet Hugo: The Speed Demon of Static Sites
Hugo isn’t just another static site generator—it’s what happens when Go developers decide to solve web publishing. Written in Go (the language that makes things go brrr), Hugo generates sites so fast you’ll think your terminal is lying to you.
Why Hugo Makes Other SSGs Look Slow
Let me put this in perspective:
- Jekyll building 1,000 pages: Goes to make coffee
- Gatsby building 1,000 pages: Watches an episode on Netflix
- Hugo building 1,000 pages: Blinks
I’m not exaggerating. Hugo can generate thousands of pages in under a second. It’s so fast that when I first used it, I ran the build command three times because I thought it had failed. Nope—it was just done before my brain could register pressing Enter.
The Real Benefits (Beyond the Speed Flex)
- No database = No database hacks: Can’t SQL inject what doesn’t exist
- Version control everything: Your entire site lives in Git
- Markdown all the things: Write content like a developer
- Stupid simple deployment: Git push = site deployed
- Free hosting options: Because why pay for static files?
GitHub Pages: The “Friend Who Always Pays”
Remember that friend who always insisted on picking up the tab? GitHub Pages is that friend, except it’s owned by Microsoft and actually has the money to back it up. Free hosting, HTTPS included, custom domains supported—what’s the catch?
There isn’t one. Well, unless you’re trying to host WikiLeaks or something. Don’t do that.
What GitHub Pages Actually Gives You
- 1GB storage: More than enough unless you’re hosting uncompressed 4K videos (please don’t)
- 100GB bandwidth/month: That’s like… a lot of visitors
- Free HTTPS: Because it’s 2025 and HTTP is basically digital streaking
- Custom domain support: yourawesome.site instead of username.github.io
- Automatic builds: Push to main, site updates. Magic.
Enter Cloudflare Pages: GitHub Pages on Performance Enhancers
Now here’s where things get spicy. While GitHub Pages is awesome, Cloudflare Pages is like GitHub Pages after it hit the gym, got a personal trainer, and started taking its vitamins.
Cloudflare Pages vs GitHub Pages: The Showdown
GitHub Pages says: “I’ll host your site for free!”
Cloudflare Pages says: “Hold my beer.”
With Cloudflare Pages you get:
- Global CDN with 200+ locations: Your site loads fast whether your visitor is in Tokyo or Toledo
- Unlimited bandwidth: Yes, unlimited. Go viral. They don’t care.
- Preview deployments: Every PR gets its own URL. Every. Single. One.
- Advanced analytics: Know thy visitors (in a non-creepy way)
- Build minutes: 500/month free, which is like 500 more than you need
- Edge functions: Run JavaScript at the edge because why not
Building the Holy Trinity: A Real-World Setup
Enough theory. Let’s build something. I’m going to show you exactly how to set up Hugo + GitHub + Cloudflare, with actual code that works, not “left as an exercise for the reader” nonsense.
Step 1: Install Hugo (The Right Way)
First, let’s get Hugo on your machine. And no, we’re not building from source like some kind of masochist.
# macOS (using Homebrew)
brew install hugo
# Windows (using Chocolatey)
choco install hugo-extended
# Linux (Ubuntu/Debian)
sudo snap install hugo
# Verify it worked
hugo version
Pro tip: Get the extended version. It includes SCSS processing and other goodies. Future you will thank present you.
Step 2: Create Your Site (With Style)
# Create new site
hugo new site my-awesome-blog
cd my-awesome-blog
# Initialize git (because we're not animals)
git init
# Add a theme (we'll use PaperMod because it's gorgeous)
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
# Tell Hugo to use the theme
echo "theme = 'PaperMod'" >> hugo.toml
Step 3: Configure Like a Pro
Here’s a hugo.toml that doesn’t suck:
baseURL = 'https://yourdomain.com'
languageCode = 'en-us'
title = 'My Awesome Blog'
theme = 'PaperMod'
paginate = 10
# Enable robots.txt
enableRobotsTXT = true
# Enable git info for last mod dates
enableGitInfo = true
[outputs]
home = ["HTML", "RSS", "JSON"]
[params]
description = "A blog about code, coffee, and controlled chaos"
author = "Your Name"
# PaperMod specific
ShowReadingTime = true
ShowShareButtons = true
ShowPostNavLinks = true
ShowBreadCrumbs = true
ShowCodeCopyButtons = true
[params.profileMode]
enabled = true
title = "Hi, I'm a Developer 👋"
subtitle = "I break things professionally"
[[params.socialIcons]]
name = "github"
url = "https://github.com/yourusername"
[[params.socialIcons]]
name = "twitter"
url = "https://twitter.com/yourusername"
# SEO optimization
[params.schema]
publisherType = "Person"
[sitemap]
changefreq = "weekly"
filename = "sitemap.xml"
priority = 0.5
Step 4: Write Your First Post (The Right Way)
hugo new posts/why-i-dumped-wordpress.md
Edit the file with proper front matter:
---
title: "Why I Dumped WordPress for Hugo"
date: 2025-01-15T10:00:00+01:00
draft: false
tags: ["Hugo", "Static Sites", "WordPress"]
categories: ["Web Development"]
description: "The story of how I escaped WordPress hell and found static site nirvana"
cover:
image: "img/wordpress-to-hugo.png"
alt: "WordPress to Hugo migration"
caption: "Best decision ever"
---
## The Beginning of the End
It started with a simple notification: "Your WordPress site has been updated to 6.x"...
Step 5: Test Locally (With Style)
# Start the development server
hugo server -D
# Open http://localhost:1313
# Marvel at the speed
# Make changes and watch them auto-reload
# Seriously, it's addictive
Step 6: Deploy to GitHub Pages
Create a .github/workflows/hugo.yaml file:
name: Deploy Hugo site to Pages
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
extended: true
- name: Build
run: hugo --minify
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: ./public
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v3
Push to GitHub and watch the magic happen.
Step 7: Supercharge with Cloudflare Pages
Sign up for Cloudflare (it’s free, stop procrastinating)
Go to Compute (Workers) > Workers & Pages
Click Create and switch to Pages
Use “Import an existing Git repository”
Connect your GitHub repository
Configure build settings:
- Build command:
hugo --minify - Build output directory:
public - Environment variables:
HUGO_VERSION = 0.143.1
- Build command:
Deploy and prepare to be amazed
Advanced Configurations That Actually Matter
Custom Domain Setup (The Right Way)
In Cloudflare Pages (Compute (Workers) > Workers & Pages):
- Click our Project
- Go to Custom domains
- Add your domain
- Follow the DNS instructions
In your
hugo.toml:baseURL = 'https://yourdomain.com'Create a
static/CNAMEfile:yourdomain.com
Performance Optimizations That Make a Difference
Image Processing Pipeline
Create a partial layouts/partials/image.html:
{{ $image := resources.Get .Params.src }}
{{ $tiny := $image.Resize "20x webp" }}
{{ $small := $image.Resize "500x webp" }}
{{ $medium := $image.Resize "1000x webp" }}
{{ $large := $image.Resize "1500x webp" }}
<figure>
<picture>
<source media="(max-width: 500px)" srcset="{{ $small.RelPermalink }}">
<source media="(max-width: 1000px)" srcset="{{ $medium.RelPermalink }}">
<source media="(min-width: 1001px)" srcset="{{ $large.RelPermalink }}">
<img
src="{{ $tiny.RelPermalink }}"
data-src="{{ $large.RelPermalink }}"
alt="{{ .Params.alt }}"
loading="lazy"
style="background-size: cover; background-image: url('{{ $tiny.RelPermalink }}');">
</picture>
{{ with .Params.caption }}<figcaption>{{ . }}</figcaption>{{ end }}
</figure>
Asset Optimization
# In hugo.toml
[minify]
minifyOutput = true
[minify.tdewolff]
[minify.tdewolff.html]
keepWhitespace = false
[minify.tdewolff.css]
keepCSS2 = true
[minify.tdewolff.js]
keepVarNames = false
SEO That Actually Works
Create layouts/partials/seo.html:
<!-- Basic Meta -->
<meta name="description" content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}">
<meta name="author" content="{{ .Site.Params.author }}">
<!-- Open Graph -->
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ with .Params.cover.image }}
<meta property="og:image" content="{{ . | absURL }}">
{{ end }}
<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ .Title }}">
<meta name="twitter:description" content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}">
{{ with .Params.cover.image }}
<meta name="twitter:image" content="{{ . | absURL }}">
{{ end }}
<!-- JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "{{ if .IsPage }}BlogPosting{{ else }}WebSite{{ end }}",
"headline": "{{ .Title }}",
"url": "{{ .Permalink }}",
{{ if .IsPage }}
"datePublished": "{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}",
"dateModified": "{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}",
{{ end }}
"author": {
"@type": "Person",
"name": "{{ .Site.Params.author }}"
},
"description": "{{ if .Description }}{{ .Description }}{{ else }}{{ .Site.Params.description }}{{ end }}"
}
</script>
Common Pitfalls and How to Avoid Them
Pitfall 1: Theme Versioning Hell
Problem: Themes update, things break.
Solution: Use git submodules and pin versions:
cd themes/PaperMod
git checkout v7.0
cd ../..
git add themes/PaperMod
git commit -m "Pin PaperMod to v7.0"
Pitfall 2: The Case of the Missing Posts
Problem: Posts don’t show up.
Solution: Check your front matter:
---
draft: false # This needs to be false!
date: 2025-01-15T10:00:00+01:00 # Must be in the past
---
Pitfall 3: Cloudflare Build Failures
Problem: Works locally, fails on Cloudflare.
Solution: Always specify Hugo version:
HUGO_VERSION = 0.143.1
HUGO_EXTENDED = true
The Results: Numbers Don’t Lie
After migrating from WordPress to Hugo + Cloudflare:
- Page load time: 4.2s → 0.3s (93% improvement)
- Lighthouse score: 67 → 100 (perfect score)
- Monthly hosting cost: $25 → $0 (100% savings)
- Security updates needed: 12/month → 0 (100% reduction in panic attacks)
- Time to deploy: 5 minutes → 30 seconds
- Coffee consumption during maintenance: Significant decrease
The Reality Check
Is Hugo + GitHub + Cloudflare perfect? No. Here’s the honest truth:
You’ll Love It If:
- You’re comfortable with Git and Markdown
- You value speed and security over features
- You enjoy having complete control
- You’re tired of WordPress maintenance
- You like saving money
You’ll Hate It If:
- You need complex user interactions
- You rely heavily on WordPress plugins
- You’re allergic to the command line
- You need a visual page builder
- You change your design weekly
Your Action Plan
- Today: Install Hugo and play with it locally
- This Week: Migrate one small project as a test
- This Month: Move your main site if the test goes well
- Next Month: Enjoy the $25/month you’re saving
The Bottom Line
I’ve been running production sites on Hugo + Cloudflare for three years now. Not once have I woken up to a hacked site, a critical security update, or a hosting bill that made me question my life choices.
Is it perfect? No. But it’s fast, secure, free to host, and lets me focus on writing content instead of maintaining infrastructure. And in a world where a WordPress site can get hacked faster than you can say “admin/admin”, that’s worth its weight in gold.
Or in this case, worth exactly $0/month. Because that’s what I pay for hosting now.
P.S. - My old WordPress site? Still running. I keep it as a honeypot for bots. The logs are hilarious. Last week, someone tried to SQL inject a comment form that doesn’t connect to a database. You can’t make this stuff up.
