Writing Field note

Web Development · 2 min read

Cloudflare Redirects for Static Blog URL Migrations

I keep changing this blog. One small Cloudflare Worker lets the URLs survive the changes while the site itself stays static.

In this article3 sections

I keep changing this blog. The Worker exists so readers do not have to care.

The site used month-based post URLs, then moved to year-and-slug URLs. Tag pages moved from /tag/ to /tags/. I also want one canonical domain instead of splitting links between www.kahwee.com and kahwee.com.

Every one of those changes leaves a trail of links in feeds, search results, bookmarks, and other posts. Static HTML cannot fix that trail on its own. A redirect has to catch the old request before the browser reaches a missing file.

That is why I originally added a Worker. As of September 2026, it also handles the contact form and engagement endpoints; the posts still render at build time.

The Worker carries the old addresses

The current configuration serves matching static assets first and runs the Worker first for /api/*. Requests without a matching asset reach the fallback Worker, which retains these redirect cases:

  • Redirect www.kahwee.com to kahwee.com.
  • Redirect old /YYYY/MM/slug/ paths to /YYYY/slug/.
  • Redirect old /tag/slug/ paths to /tags/slug/.

Everything else goes straight to the generated asset bundle. The Worker also serves the blog’s custom 404 page when no file exists.

The Worker renders no posts. Its page-routing job is compatibility; the API endpoints are separate runtime work. The tag redirect pattern is the clearest example.

Static lets the runtime stay boring

Astro now turns the Markdown and templates into a dist/ directory before deployment. Cloudflare serves that directory as static assets. Most requests never need application logic.

That is the stack I want for a blog. Publishing a post should generate a page, upload files, and finish. Why I built a static blog covers the original decision. The Worker preserves the consequence of changing my mind later.

The hosting move from Pages to Workers kept that contract intact. The current Astro build produces the static dist/ bundle. Wrangler deploys that directory alongside the Worker. The migration note records that change because it was deliberately boring.

Keep the current stack distinct from the migration

The older migration notes describe Bunki and a separate image-hosting arrangement. This repository now uses Astro and local article assets. I would not use those older notes as an inventory of today’s services.

Redirects still let me change the publishing setup while preserving old page addresses. That is the part of the design I have kept.

Was this useful?

What was missing?

Thanks for the feedback.