I wanted a blog that was fast, free to host, and didn’t require me to manage a server. This post is a step-by-step account of how I built exactly that — using Hugo to generate the site and Cloudflare Pages to serve it.
No prior experience needed. If you can use a terminal and have a GitHub account, you can follow along.
First, understand what you’re building
Before touching any tools, it helps to understand what’s actually happening.
A traditional website works like this: a visitor requests a page → your server runs code → generates HTML → sends it back. Every request triggers computation.
A static site flips this: you generate all the HTML once on your own machine, then upload the result. When a visitor arrives, Cloudflare just hands them a pre-built file. No server, no database, no computation at request time. This makes it extremely fast and essentially free to host.
Hugo is the tool that generates those HTML files from your content. You write posts in plain Markdown, run one command, and Hugo produces a complete website. Cloudflare Pages is the free hosting layer — it serves your files from data centers around the world so your site loads fast for everyone.
What you’ll need
- A terminal (Terminal on Mac, any shell on Linux, WSL on Windows)
- Git installed
- A GitHub account
- A Cloudflare account (free tier is enough)
- About 30 minutes
Step 1 — Install Hugo
Hugo is a single binary. Install it with your package manager:
Mac:
brew install hugo
Linux:
sudo snap install hugo
Windows:
winget install Hugo.Hugo.Extended
Verify it worked:
hugo version
You should see something like hugo v0.162.1+extended. The extended variant is important — some themes require it for SCSS processing.
Step 2 — Create a new site
hugo new site my-blog
cd my-blog
git init
This creates a folder with Hugo’s expected structure:
my-blog/
├── content/ ← your posts go here
├── static/ ← images, fonts, files
├── layouts/ ← HTML templates (usually from a theme)
├── archetypes/ ← templates for new content
└── hugo.toml ← site configuration
You don’t need to touch most of this yet.
Step 3 — Add a theme
Hugo sites are unstyled by default. Themes provide the look and the layout templates. I used PaperMod — it’s minimal, fast, and well-maintained.
Hugo can pull themes as Go modules, which is cleaner than copying files into your repo:
hugo mod init github.com/your-username/my-blog
Then open hugo.toml and add:
[module]
[[module.imports]]
path = "github.com/adityatelange/hugo-PaperMod"
Pull the theme:
hugo mod tidy
Step 4 — Configure your site
Replace the contents of hugo.toml with a basic config:
baseURL = 'https://your-site.pages.dev/'
title = 'Your Name'
paginate = 10
[module]
[[module.imports]]
path = "github.com/adityatelange/hugo-PaperMod"
[params]
ShowReadingTime = true
ShowPostNavLinks = true
ShowBreadCrumbs = true
ShowCodeCopyButtons = true
ShowToc = true
[[menus.main]]
name = "Blog"
url = "/blog"
weight = 10
Change baseURL to match your Cloudflare Pages domain (you’ll get this in Step 7 — you can come back and update it).
Step 5 — Write your first post
hugo new blog/my-first-post.md
This creates content/blog/my-first-post.md with front matter already filled in:
---
title: "My First Post"
date: 2026-06-05
draft: true
---
Write your post here in plain Markdown.
When draft: true, Hugo won’t publish it. Change it to false when you’re ready.
Write your post in Markdown. Hugo supports all standard Markdown syntax — headings with #, bold with **text**, code blocks with triple backticks, links with [text](url).
Preview it locally:
hugo server -D
The -D flag includes draft posts. Open http://localhost:1313 in your browser. Hugo watches for file changes and reloads automatically.
Step 6 — Push to GitHub
Cloudflare Pages deploys from a Git repository, so you need your site on GitHub.
Create a .gitignore to exclude the generated output:
public/
resources/
.hugo_build.lock
Create a new repository on GitHub (call it my-blog), then:
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/your-username/my-blog.git
git push -u origin main
Step 7 — Deploy on Cloudflare Pages
- Log in to Cloudflare Dashboard
- Go to Workers & Pages → Create → Pages
- Click Connect to Git and authorize GitHub
- Select your
my-blogrepository - Under Build settings, set:
- Build command:
hugo mod tidy && hugo --minify - Build output directory:
public
- Build command:
- Click Save and Deploy
Cloudflare clones your repo, runs the build command, and publishes the public/ folder. Your site gets a free *.pages.dev subdomain.
Now go back to hugo.toml and update baseURL to your new domain, commit, and push. Cloudflare will redeploy automatically on every push to main.
How it all fits together
Here’s the full picture:
You write Markdown
↓
Hugo converts it to HTML (build step, runs on Cloudflare)
↓
Cloudflare stores the HTML files
↓
Visitor requests your site
↓
Cloudflare serves the pre-built file from the nearest data center
There is no server running your code. There is no database. Cloudflare is essentially a very fast, globally distributed file server — and the free tier is generous enough that a personal blog will never hit any limits.
What’s next
A few things worth exploring once your site is live:
- Custom domain — Cloudflare makes this straightforward if your domain is also managed there
- Analytics — Cloudflare Web Analytics is free and privacy-friendly, no JavaScript tracking required
- Open Graph images — add a social preview image so your posts look good when shared on Twitter/LinkedIn
- Comments — giscus uses GitHub Discussions as a comment backend, no database needed
The best part of this setup: once it’s running, publishing a new post is just writing a Markdown file and pushing to GitHub. Everything else is automatic.