My Cloudflare Workers Migration: The Good, The Bad, and The Confusing


Introduction
I built this little URL shortener for myself. Think of it as a personal version of dub.co where I can type short, memorable links instead of full URLs. For example, when I share my GitHub profile, I can just type "arpit.im/gh" instead of typing out the whole "github.com/arpitdalal" address. Super convenient when sharing links or adding them to my resume! Plus, there's a hidden superpower: when I change usernames on various platforms (which happens more than I'd like to admit), I only need to update one redirect in my service rather than hunting down every instance of that link across the internet.
This humble URL router started its life as a traditional Node.js and Express app running happily on fly.io. It was comfortable, familiar territory. Until I decided to shake things up and migrate the whole thing to Cloudflare Workers using Bun and Hono.
Why would I abandon a perfectly functional setup for the wild west of edge computing? Well, that's where my adventure begins, and let me tell you – it's been quite the roller coaster ride!
Why I Jumped Ship
"Why mess with something that works?" Fair question! My Node.js and Express setup was solid and reliable, quick to build and easy to modify, despite the occasional TypeErrors that JavaScript loves to surprise you with.
Since I was planning to migrate to TypeScript anyway, I figured this was the perfect opportunity to expand my horizons. Why just add types when I could learn something completely new in the process?
I initially chose the familiar stack to ship quickly (a decision we've all made). But once my project was live and stable, I couldn't ignore that developer urge to evolve it into something more, to actually learn from this little side project instead of letting it stagnate.
That’s when Hono caught my eye because it has a similar API to Express (which is pretty robust), but it's supposedly "blazingly fast" and comes with native TypeScript support. Win-win!
Life got busy (as it does), and a couple of months flew by. When I finally circled back to this idea, I thought, "Why stop at just changing the framework? Let's go all in and try a new runtime too!"
I was torn between Deno, Bun, and Cloudflare's workerd. This was my first deep dive into CF Workers, and what really blew me away was learning they run on V8 Isolates with practically zero cold-start time.
That last point was a game-changer! AWS Lambdas and its different flavours from Netlify or Vercel have pretty noticeable cold-starts. That’s why I chose a long-running server on fly.io to avoid those painfully slow serverless cold-starts. Nobody wants to wait ages for a simple redirection, right? Plus, Cloudflare's edge network meant my app would run in multiple regions worldwide, not just from my lonely fly.io server in Toronto.
I'd been using npm as my package manager for ages, but kept hearing about faster alternatives. The benchmarks for pnpm and bun looked impressive, and I was curious. I ultimately went with bun, partly for the speed, but mostly because I wanted to experiment with their cutting-edge approach to JavaScript tooling.
So that settled it - Hono as the framework, Bun for the tooling, and Cloudflare Workers as the infrastructure. Time to jump in!
The Good Stuff (aka Why I Don't Completely Regret My Decision)
Amazing Community Support - The Hono community absolutely loves Cloudflare Workers, which meant there were tons of starter guides and examples. This saved me hours of head-scratching!
Documentation That Doesn't Make You Cry - Refreshingly, Hono's docs for Cloudflare Workers integration are actually current and comprehensive. It's rare to find such well-maintained documentation when one tool integrates with another. I didn't need to waste hours digging through GitHub issues or outdated guides to get things working, the answers were right there in the docs.
Surprisingly Good Library Support - The Cloudflare Workers ecosystem surprised me with its maturity, far more libraries offer native support than I expected. From testing to rate limiting, I found packages for most common needs without having to build workarounds.
Super Simple Local Development - Setting up my local development environment was remarkably smooth. The community starter templates combined with wrangler's local dev server had me coding productively within minutes, not hours, which is a welcome change from my previous serverless experiences.
Testing That Doesn't Suck - Testing with Hono turned out to be surprisingly pleasant. Cloudflare's vitest plugin effectively simulated the production environment in my test suite, eliminating those frustrating "works locally, fails in production" moments that plague serverless development.
The Not-So-Good Stuff (aka The Parts That Made Me Question My Life Choices)
Cloudflare Dashboard: The Labyrinth - Is it just me, or is the Cloudflare dashboard intentionally designed to confuse people? I spent more time than I'd like to admit just trying to find the right settings.
Domain Setup From Hell - To serve my worker on a custom domain, I had to change my nameservers to Cloudflare. This seemingly simple change took my domain down for over HALF A DAY. The more baffling thing is that I have no idea why it took that long and there’s no way for me to expedite it or fix it. Not exactly what I'd call a smooth transition!
Wrangler: Powerful but Mysterious - Wrangler (Cloudflare's CLI tool) is incredibly powerful, but it's also incredibly confusing. The learning curve is steeper than it needs to be. Maybe it’s a skill issue?
Wrangler Config Nightmare - Cloudflare forces you to stuff everything into wrangler.jsonc/.toml files: environment variables, domain zone IDs, KV store configs… you name it! This creates an immediate security dilemma: how do I version control the wrangler config file without exposing my secrets on GitHub? I wasted countless hours putting together a secure CI/CD pipeline. My "solution"? Storing secrets in GitHub Actions and using scripts to dynamically replace placeholders in the wrangler config during deployment. It works, but feels like a clunky workaround for what should be a solved problem. While Netlify and Vercel elegantly separate configuration from secrets through an intuitive dashboard, Cloudflare's approach feels like it was designed by people who've never had to manage a production deployment pipeline for an open source project.
Mysterious Versioning System - Instead of using sensible semantic versioning like every other tool in the JavaScript ecosystem, Cloudflare decided to implement "compatibility dates" in wrangler configs that magically change available types and behaviors. Change one date and suddenly your TypeScript throws errors because APIs have different signatures? Fun times! I still don't fully understand the reasoning behind this approach - there's a reason npm package versions exist and are universally adopted. This unconventional system makes it unnecessarily difficult to predict how your code will behave across environments or when upgrading.
Too Much Magic, Not Enough Explanation - Some types are just magically available in the workerd environment, which becomes a real headache when your tests are running in a non-workerd environment.
Debugging in the Dark - Since it's not a long-running server, debugging when something goes wrong can feel like trying to find a specific snowflake in a blizzard.
What I Learned From All This
Would I recommend Cloudflare Workers? Yes, but know what you're getting into.
Despite all my griping, I don't regret making the switch. My links now load noticeably faster thanks to Cloudflare's global edge network - when someone clicks my URL in Australia, they're not waiting for a server in Toronto to respond. Yes, I traded my zero-cold-start setup for occasional millisecond delays, but they're so minimal that neither I nor my users can detect them. The unexpected bonus? Cloudflare's built-in bot protection system. My old setup would occasionally get hammered by random bots, causing unexpected spikes and headaches. Now I sleep better knowing there's an enterprise-grade security system standing guard over my humble little URL shortener. The migration headaches were real, but for my specific use case, the benefits have outweighed the costs.
That said, if I could do it again, I would spend more time upfront understanding Cloudflare's ecosystem before diving in. Their approach is fundamentally different from traditional servers, and that requires a mental shift.
For anyone considering a similar move, my advice would be: spend some time to understand how CF works, start with a small project, expect some frustration with the config and deployment process, but stick with it because the performance and security benefits from Node.js are worth it in the end.
Here’s the before and after diff for my project.
Have you tried Cloudflare Workers or similar edge computing platforms? Was any of this a skill issue? I'd love to hear about your experiences and how you overcame similar challenges!
Subscribe to my newsletter
Read articles from Arpit Dalal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Arpit Dalal
Arpit Dalal
I am a web developer enthusiastic about all things about React and TS!