Greg Vedders
  • About
  • Tags
  • Posts

Rebuilding gregvedders.com Without a Hugo Theme

Removing the Ananke theme, inlining CSS, adding search, and fixing the things PageSpeed actually cares about.

posts
June 21, 2026 • 5 min read • 1017 words

I have been running this site on Hugo and Cloudflare Pages for a while now. I wrote about that setup back in 2024. It worked. The site was fast enough, deployment was painless, and I did not think about it much.

Then I started paying attention to what the site was actually shipping.

Not in a vague “make it faster” way. I ran PageSpeed Insights, looked at the network waterfall, and realized I was loading a theme I barely used anymore, pulling CSS from paths I did not control, and carrying around a Git submodule I had stopped updating.

So I rebuilt the site without a theme.

Not “switched to a different theme.” Removed the theme entirely.


What was wrong

The site used the Ananke theme as a Git submodule. That is a common Hugo pattern, and for a long time it was fine.

Over time, a few things started to bother me:

  • The submodule was dead weight. I was not pulling theme updates. I was overriding most of the layout anyway.
  • CSS came from everywhere. Theme assets, generated Ananke paths, extra requests — more moving parts than a personal blog needs.
  • Image handling was inconsistent. Featured images worked on some pages and broke on others depending on which partial the list view called.
  • There was no search. For a site whose whole purpose is “notes I might need later,” that felt silly.

None of this was catastrophic. The site worked. But it was harder to change than it should have been, and the performance numbers reflected that.


The approach: own the stack

I removed the Ananke submodule and moved everything into the project:

  • assets/css/site.css — one stylesheet, written for this site
  • layouts/ — templates live here now, not in a theme directory
  • No themes/ directory at all

That sounds like more work. In practice, it was less work than fighting a theme I did not fully understand anymore.

The CSS is small — a few kilobytes. In production, Hugo inlines it in the <head>, so the browser does not need a separate CSS request before it can render the page.

Layouts are boring on purpose. A base template, a post layout, list pages for /posts/, taxonomy pages for tags. Nothing clever. Just the structure this site actually uses.


Images and headers

This site uses Hugo Extended for image processing. That matters.

Featured images get resized and converted to WebP. Header backgrounds use a crop defined in config (1600x560 TopRight for the wide cover image). The logo in the nav is resized so the header is not downloading a full-resolution asset on every page.

hugo version needs to say extended — otherwise image builds fail or silently skip processing. Match your Cloudflare build environment when you can; mine is Hugo 0.163.3 Extended.


Search with Pagefind

Static sites do not get search for free. Hugo builds HTML files; nothing indexes them unless you add that step.

I went with Pagefind. After Hugo builds the site, Pagefind crawls the output and writes a client-side search index into public/pagefind/. No server. No Elasticsearch. No monthly bill.

The Cloudflare build command looks like this:

hugo --cleanDestinationDir -b https://example.com --minify && npx -y pagefind --site public

Search shows up in the nav. Ctrl+K / Cmd+K opens it. For a personal site with a few dozen posts, it is exactly enough.


Tags, sitemap, and the small stuff

While I was in there, a few other cleanup items made the site feel more intentional:

  • Tags in the nav — /tags/ lists everything with a proper index page, not a wall of unstyled links
  • enableLastmod in the sitemap — search engines get accurate last-modified dates
  • Custom SPL syntax highlighting — Hugo’s highlighter does not know Splunk’s query language; I added a render hook so security posts look right in the browser

That last one is niche. But this is a security blog. If I am going to write Splunk searches on the site, I want them to look like Splunk searches.


PageSpeed: what actually moved the needle

I am not going to pretend I optimized my way to perfection. I got 100 on desktop and 99 on mobile in PageSpeed Insights lab tests, which is good enough for me.

What helped on the build:

  • Inlined CSS (no render-blocking stylesheet)
  • Processed, right-sized images
  • No theme JavaScript
  • Clean HTML output from Hugo with --minify

What still shows up in lab tests but is not in your Hugo project:

  • Cloudflare Rocket Loader — if enabled, it injects script that hurts cache and render metrics
  • Cloudflare Web Analytics beacon — third-party script with a short cache TTL

Those are dashboard toggles. Worth knowing about if you are chasing scores and cannot figure out why the lab report mentions scripts you never added.


Deploy and day-to-day workflow

Cloudflare Pages builds on every push to whatever Git repo you connect. Output directory is public. The site is still static HTML.

Local preview:

hugo server

Search only works locally after Pagefind has indexed a full build:

hugo --cleanDestinationDir -b https://example.com --minify && npx -y pagefind --site public
hugo server --disableFastRender

After removing a theme, clean stale build output once before your next deploy:

rm -rf public/ resources/

Leftover resources/_gen paths from the old theme caused odd image behavior until I did that.


Was it worth it?

For this site, yes.

I lost the convenience of a pre-built theme. I gained a codebase I can actually explain. When something looks wrong, I know which file to open. When I want to add search or fix how tag pages render, I do not have to reverse-engineer Ananke first.

If you are running Hugo with a theme you have not touched in years, it might be worth asking whether you still need the theme — or whether you need five layouts and a stylesheet you control yourself.

This site is not a framework. It is a blog. Keeping it simple turned out to be the performance win I was looking for.


Quick reference

SettingValue
Build commandhugo --cleanDestinationDir -b https://example.com --minify && npx -y pagefind --site public
Output directorypublic
Hugo version0.163.3 (Extended)
Share this post

About

Greg Vedders writes about information security, troubleshooting, photography, and the occasional unexpected fix.

Recent Posts

  • Introducing Signage Suite — Self-Hosted Wall Displays in PHP
  • Hardening a Public Honeypot Server
  • What Happens When You Leave a Door Slightly Open?
  • Tunnels All the Way Down

Tags

Hugo Cloudflare Self-Hosting

Related Posts

  • Tunnels All the Way Down
  • Exposing Services Safely with Cloudflared Tunnels
  • How to Use Hugo with Cloudflare Pages
  • Hardening a Public Honeypot Server
© Greg Vedders 2026