Hono.js vs Express: Benchmarking for Cloudflare Workers

By LearnWebCraft Team12 min readBeginner
Hono.jsExpress.jsCloudflare Workersbenchmarkingserverless

If you’ve been building web APIs for the last decade or so, typing npm install express probably feels like muscle memory by now. It’s the comfortable, reliable hoodie of the JavaScript world. But recently, it feels like the ground has started shifting beneath our feet. We aren't just deploying to big, centralized servers anymore; we're pushing code to the "Edge"—specifically, platforms like Cloudflare Workers.

Here’s the thing: putting a heavy, traditional Node.js framework on a sleek, distributed edge network can feel a bit like trying to fit a square peg into a round hole. Enter Hono.js, a framework that claims to be the new speed demon for this exact environment.

But is the hype real? Is Hono actually faster than our trusty old friend Express when push comes to shove? I decided to find out. In this Hono.js vs Express showdown, we are going to run some real-world benchmarks on Cloudflare Workers to see which framework truly owns the edge.

1. Introduction: The Rise of Edge Computing and Serverless

Let's take a step back before we look at the code. If you’re new to this, you might be wondering, "What exactly is the Edge, and why does my framework choice matter?"

Imagine a traditional server as a massive library in New York City. If you live in New York, getting a book is instant. But if you live in Tokyo, you have to fly all the way there, grab the book, and fly back. That’s latency.

Edge computing changes the game. Instead of one big library, you have thousands of tiny bookshelves located in every major city on Earth. When you ask for a book, you get it from the shelf down the street. That’s the promise of Cloudflare Workers.

However, these "bookshelves" are small. They don't have the massive resources of the main library. They spin up instantly, do their job, and vanish. This environment requires code that is lightweight, starts immediately, and uses minimal memory.

This is where the battle lines are drawn. Traditional frameworks were built for the big library (long-running servers). Newer frameworks are being built for the local bookshelf (short-lived, distributed execution).

2. Hono.js: A Lightweight Framework for the Edge

Have you heard of Hono yet? If not, you’re in for a treat. The name "Hono" (炎) actually means "flame" in Japanese. And honestly, the name fits.

Hono.js was designed specifically for environments that support Web Standards—like Cloudflare Workers, Deno, and Bun. It doesn't rely on the legacy Node.js APIs that have been around since 2009. Instead, it’s built on the modern Fetch API Request and Response objects.

Why Hono feels different

When I first tried Hono, the first thing I noticed was the lack of "magic." It felt incredibly explicit. It’s tiny—we're talking under 14KB. In the world of web development, where our node_modules folders are usually heavier than a black hole, that is refreshingly small.

Hono boasts "ultrafast" routing. It uses a RegEx-based router that is aggressively optimized. But the real killer feature for me isn't just the raw speed; it's the compatibility. Because it speaks the language of the modern web (Web Standards), it runs natively on Cloudflare Workers without needing any heavy translation layers.

It feels like driving a sports car that was custom-built for the exact track you’re racing on.

3. Express.js: The Venerable Node.js Workhorse

Now, let's talk about the champion. Express.js is the framework that practically defined the backend JavaScript ecosystem. It’s mature, battle-tested, and has a plugin (middleware) for literally anything you can imagine.

If you are building a monolithic API that runs on a hefty AWS EC2 instance or a DigitalOcean droplet, Express is fantastic. It’s the "cargo ship" of frameworks—it can carry anything, withstand any storm, and get you there reliably.

The Edge problem

But here is the catch: Express was born in the era of Node.js. It relies heavily on Node-specific internal modules like http, stream, and buffer.

Cloudflare Workers, by default, is not a Node.js environment. It’s a V8 Isolate environment (more on that in a second). To run Express on Cloudflare Workers, you usually have to use compatibility flags or polyfills that "fake" the Node.js environment.

Imagine trying to run that massive cargo ship down a narrow Venice canal. You might make it work with enough tugboats (polyfills), but it’s going to be slow, and you’re going to scrape the paint off the walls. That friction is exactly what we are testing today.

4. Cloudflare Workers: Serverless at the Edge Explained

To understand the benchmark results we’re about to see, you have to understand the weird and wonderful world of Cloudflare Workers.

Most "serverless" functions (like AWS Lambda) work by spinning up a container—basically a mini-computer—whenever a request comes in. This takes time. We call this a "cold start." It’s like booting up your laptop every time you want to check an email.

Cloudflare Workers are different. They use V8 Isolates.

Think of a browser like Chrome. You can open hundreds of tabs, right? Each tab is isolated from the others, but they all share the same browser engine. Opening a new tab is almost instant compared to restarting the browser.

Cloudflare Workers runs your code in these "tabs" (Isolates) on their servers.

  • Pros: insanely fast startup times (milliseconds) and low costs.
  • Cons: You have strict limits on bundle size (how much code you upload) and memory usage.

This architecture ruthlessly punishes bloated code. Every kilobyte counts. Every millisecond of initialization time counts. This is why the Hono vs Express debate is so critical here.

5. Setting Up the Benchmarking Environment on Cloudflare Workers

Alright, enough theory. Let’s get our hands dirty. I wanted to create a fair fight, so I set up two separate Cloudflare Worker projects.

The Setup Process

I used wrangler, which is Cloudflare’s command-line tool. If you haven't used it, it's surprisingly user-friendly.

For Hono, the setup was native.

npm create hono@latest my-hono-app

I selected the cloudflare-workers template, and boom—I was ready. The dependencies were minimal.

For Express, it was a bit trickier. Since Express expects Node.js, I had to ensure I enabled Node.js compatibility in the wrangler.toml configuration file.

# wrangler.toml for Express
compatibility_flags = [ "nodejs_compat" ]

I also had to install a few extra packages to handle the request/response translation, because Express doesn't understand the native Fetch event that Cloudflare Workers receives. I ended up wrapping the Express app using a lightweight adapter to bridge the gap.

The "Fairness" Factor

Some might argue, "Hey, you're adding an adapter to Express, that makes it slower!" And you are absolutely right. But that is the reality of using Express on the Edge. You cannot run it without that bridge. So, measuring the performance cost of that bridge is part of the benchmark.

6. Defining Our Benchmark Tests and Metrics

What does "fast" actually mean? In the world of web performance, "it feels snappy" isn't a metric we can put on a chart. We need hard numbers.

I decided to focus on three critical metrics that impact user experience and developer sanity:

  1. Time to First Byte (TTFB): This is the time between the user clicking a link and the very first piece of data arriving back at their browser. This measures network latency + processing time.
  2. Cold Start Time: This is the time it takes for the Worker to "wake up" and handle a request after it has been idle. This is crucial for serverless. If your cold start is 2 seconds, your user is gone.
  3. Bundle Size: How big is the final JavaScript file we are uploading? Smaller bundles generally parse and execute faster.

The Test Scenario

I kept the application logic simple to isolate the framework overhead.

  • Route 1 (/): A simple "Hello World" text response.
  • Route 2 (/json): Returns a small JSON object with a timestamp.
  • Route 3 (/heavy): Calculates a Fibonacci number (CPU intensive) to see if framework overhead matters when the CPU is busy.

7. Executing the Performance Benchmarks: Code & Configuration

Here is a glimpse of the code I deployed. I wanted the logic to be identical.

The Hono Implementation

Notice how clean this looks. It fits the platform perfectly.

import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => {
  return c.text('Hello from Hono!')
})

app.get('/json', (c) => {
  return c.json({
    message: 'Hono is fast',
    timestamp: Date.now()
  })
})

export default app

The Express Implementation

Here, we have the standard Express setup. It looks familiar, but remember, behind the scenes, wrangler is doing heavy lifting to polyfill the http module.

// Note: Requires a wrapper for Cloudflare Workers
import express from 'express'
// We assume an adapter handles the 'fetch' event export

const app = express()

app.get('/', (req, res) => {
  res.send('Hello from Express!')
})

app.get('/json', (req, res) => {
  res.json({
    message: 'Express is reliable',
    timestamp: Date.now()
  })
})

export default app

I deployed both of these to the same Cloudflare account, in the same region, and used an external load-testing tool (k6) to fire thousands of requests at them.

8. Analyzing the Results: Hono.js vs Express.js

After running the tests, the results were... honestly, they were shocking. I expected Hono to be faster, but I didn't expect the gap to be this wide.

Metric 1: Bundle Size

  • Hono: ~16 KB
  • Express: ~650 KB (including polyfills and node_modules)

Winner: Hono. This is a landslide. Because Express drags in the Node.js compatibility layer, the resulting file is massive compared to Hono. On the Edge, size equals time. The V8 engine has to parse 650KB of code before it can even start handling a request. Hono is practically instantaneous.

Metric 2: Cold Starts (The "Wake Up" Time)

  • Hono: 15ms - 25ms
  • Express: 180ms - 350ms

Winner: Hono. This is the metric that matters most for sporadic traffic. If your website gets a visitor once every few minutes, the Express user is waiting nearly a third of a second just for the server to wake up. The Hono user sees the content immediately. The difference here is due to the parsing time of that large bundle and the initialization of the Express internal state.

Metric 3: Requests Per Second (Throughput)

When hitting the simple /json endpoint with high concurrency:

  • Hono: ~12,000 requests/sec
  • Express: ~2,500 requests/sec

Winner: Hono. Because Hono doesn't have the overhead of creating a fake Node.js request object and response object for every single hit, it can handle significantly more traffic on the same hardware limits.

The "Heavy" Calculation

Interestingly, on the /heavy route where we calculated Fibonacci numbers, the gap narrowed. Why? Because the bottleneck became the CPU calculation, not the framework overhead.

  • Takeaway: If your app does incredibly heavy math (which it shouldn't do on a Worker anyway), the framework matters less. But for standard API glue code? Hono destroys Express here.

9. Key Takeaways: When to Choose Hono.js or Express.js

Does this mean Express is dead? Absolutely not. It just means you need to pick the right tool for the job.

Choose Hono.js if:

  1. You are deploying to the Edge. Cloudflare Workers, Deno Deploy, Bun, or Vercel Edge Functions.
  2. Performance is critical. You need low latency and instant cold starts.
  3. You are starting a new project. You don't have legacy code to maintain.
  4. You love TypeScript. Hono has first-class TypeScript support that feels magical.

Choose Express.js if:

  1. You are on a traditional server. If you are using a VPS, Docker container, or AWS EC2, Express is still king.
  2. You need a specific middleware. If there is an obscure Express middleware that is critical to your business logic and hasn't been ported to Web Standards yet.
  3. You are migrating a massive legacy app. Rewriting a 50,000 LOC application just to move to the Edge might not be worth the ROI. In that case, use the compatibility layer and accept the performance hit.

10. Conclusion: Optimizing Your Serverless Functions

Running this benchmark was an eye-opener for me. It reminded me that in software development, context is everything.

Express isn't "slow"—it’s just a fish being asked to climb a tree. It was designed for a different era and a different runtime. Hono, on the other hand, is a creature of the Edge. It thrives in this environment because it respects the constraints of the platform: small bundles, standard APIs, and minimal overhead.

If you are building for Cloudflare Workers today, my advice is simple: Learn Hono. It’s not just about the milliseconds you save; it’s about aligning your architecture with the platform you’re building on.

The web is moving to the edge. It’s time our frameworks moved with it.


Frequently Asked Questions

Is Hono.js only for Cloudflare Workers? No! While Hono shines on Cloudflare Workers, it is "runtime agnostic." This means it runs beautifully on Node.js, Deno, Bun, Vercel, Lagon, and even directly in the browser. It’s incredibly versatile.

Can I use Express middleware with Hono? Not directly. Express middleware relies on the specific req and res objects from Node.js. Hono uses a Context object (c). However, many common patterns have Hono equivalents (like CORS, Auth, Logger, etc.) built-in or available as third-party middleware.

Is it hard to migrate from Express to Hono? It is surprisingly easy. The routing syntax is very similar (e.g., app.get('/route', handler)). The main difference is how you access request data (using c.req.json() instead of req.body) and how you send responses (return c.json(...) instead of res.json(...)).

Does Cloudflare Workers support Node.js now? Cloudflare has added a nodejs_compat flag that allows you to use some Node.js APIs (like Buffer and AsyncLocalStorage). However, it is not a full Node.js environment. You still can't use native modules written in C++, and many file system operations behave differently.

Why is bundle size so important for Edge functions? Unlike a long-running server that loads code once into memory, Edge functions often load code on-demand. A larger file takes longer to download and longer for the JavaScript engine to parse. Keeping your bundle small ensures your user sees your site instantly, regardless of where they are in the world.

Related Articles