Skip to main content

Express vs Hono in 2026: Legacy vs Modern Node.js

·PkgPulse Team
0

TL;DR

Express has 20x more downloads but Hono is the better choice for new projects. Express (35M+ weekly downloads) won through ubiquity and age. Hono (1.8M) wins on TypeScript, performance, and modern runtime support. For greenfield APIs in 2026, Hono is the correct default. For maintaining Express apps, stay — migration isn't worth it for stable codebases.

Key Takeaways

  • Express: ~35M weekly downloads — Hono: ~1.8M (npm, March 2026)
  • Hono is 4-5x faster on Node.js; much faster on Bun
  • Express has no TypeScript — Hono is TypeScript-first with request type inference
  • Hono runs on Cloudflare Workers — Express cannot (Node.js APIs only)
  • Hono is Express-compatible — familiar API, easy learning curve

The Gap in Context

Express's download dominance is a trailing indicator. It powers millions of production Node.js applications — most of which aren't being rewritten. The install numbers reflect maintenance of existing systems, not new project adoption. When a company runs 50 microservices built in 2018 on Express, every CI pipeline, every npm install, every Docker build increments that weekly download counter. None of those numbers represent new project adoption.

New project starts tell a different story. In 2026, Hono, Fastify, and Elysia have captured the majority of net-new backend Node.js applications. Express is still started for quick prototypes by developers who know it, but the ecosystem is clearly shifting. The reasons are straightforward: Express was designed for a world without TypeScript, before async/await was standard, and before edge runtimes existed. None of those assumptions hold anymore.

Express 4.x shipped in 2014. The framework has received security patches and minor updates since then, but its core architecture is unchanged. It still uses Node.js's callback-based http.createServer() under the hood. It still expects synchronous or callback-based middleware. TypeScript support is provided by community-maintained @types/express declarations that bolt types onto an API never designed for them. The framework works — but it carries twelve years of architectural decisions made before modern JavaScript existed.

Understanding the practical differences between the two frameworks comes down to a few key dimensions: API design, runtime portability, middleware maturity, and performance characteristics. Each area reveals a genuine gap between what Express was designed to do and what developers building new applications in 2026 actually need.


API Design Comparison

The surface-level API difference between Express and Hono is small — both use app.get(), app.post(), and similar methods. The meaningful difference is what you get from the request and response objects, and how much the compiler can help you.

// Express — callback-based, no types
const express = require('express');
const app = express();
app.use(express.json());

app.get('/users/:id', async (req, res) => {
  // req.params.id is string | undefined — no type safety
  const user = await db.user.findUnique({
    where: { id: req.params.id }
  });

  if (!user) return res.status(404).json({ error: 'Not found' });
  res.json(user);
});

app.post('/users', async (req, res) => {
  // req.body is any — needs manual validation
  const { name, email } = req.body;
  if (!name || !email) return res.status(400).json({ error: 'Missing fields' });

  const user = await db.user.create({ data: { name, email } });
  res.status(201).json(user);
});

app.listen(3000);
// Hono — TypeScript-first, web standards
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const app = new Hono();

app.get('/users/:id', async (c) => {
  const id = c.req.param('id'); // typed as string
  const user = await db.user.findUnique({ where: { id } });

  if (!user) return c.json({ error: 'Not found' }, 404);
  return c.json(user); // response type inferred
});

app.post('/users',
  zValidator('json', z.object({
    name: z.string().min(1),
    email: z.string().email(),
  })),
  async (c) => {
    const body = c.req.valid('json'); // { name: string, email: string }
    const user = await db.user.create({ data: body });
    return c.json(user, 201);
  }
);

export default app; // Works on Cloudflare Workers

The type safety difference is meaningful in large codebases. req.body being any in Express leads to undetected type errors at runtime that TypeScript should have caught. Hono's c.req.valid('json') returns the validated, typed body — your editor will autocomplete field names and flag mismatches immediately. When the schema changes, the TypeScript compiler surfaces every location that needs to be updated rather than discovering breakage in production.

There's also a conceptual difference in how the two frameworks treat the Request and Response objects. Express uses its own proprietary req and res objects — augmented versions of Node.js's IncomingMessage and ServerResponse. These objects have Express-specific methods like res.json(), res.send(), and req.body that don't exist in standard JavaScript. Hono uses the Web Standard Request and Response objects (the same ones available in browsers, Deno, and Cloudflare Workers) as its foundation. Code written against Hono's context object works the same whether it runs on Node.js, Cloudflare Workers, or Bun — because the underlying primitives are part of the web platform standard, not framework-specific inventions.


Runtime Support: Hono's Key Advantage

Express is Node.js-only. It is built on top of Node.js's http module and depends on Node-specific APIs that do not exist in other runtimes. This makes Express incompatible with Cloudflare Workers, Bun's native HTTP server, Deno Deploy, Vercel Edge Functions, and AWS Lambda@Edge.

Hono was designed from the start to run anywhere. The same application code deploys across:

// Cloudflare Workers — export default app
export default app;

// Bun
import { serve } from '@hono/node-server';
Bun.serve({ fetch: app.fetch });

// Node.js
import { serve } from '@hono/node-server';
serve(app);

// Deno
Deno.serve(app.fetch);

// Vercel Edge
export const config = { runtime: 'edge' };
export default app.fetch;

For teams working across multiple deployment targets — or who want the option to migrate from Node.js to Cloudflare Workers in the future — Hono's portability is a genuine architectural advantage. With Express, you're locked into the Node.js runtime for the lifetime of the application. The architecture decision you make at project start dictates your deployment options for years.

The Cloudflare Workers deployment specifically is worth highlighting. Workers has become a production-ready platform for APIs in 2026: globally distributed across 300+ data centers, cold-start times under 5ms, and a pricing model that scales to zero. Workers run on Cloudflare's V8 isolate runtime, which is why Express — which calls require('http') — can't run there at all. For any team evaluating Cloudflare's developer platform, Workers KV, D1, or R2 storage, Express is simply off the table as the API layer. Hono is the default choice precisely because it was designed for this environment from day one.


Middleware Ecosystem

Express has over a decade of battle-tested middleware. Packages like helmet (security headers), morgan (HTTP logging), cors, express-rate-limit, express-session, passport for auth, and multer for file uploads are all mature, widely adopted, and actively maintained. If you have a specific middleware requirement, there is almost certainly an Express package for it.

// Express — vast middleware ecosystem
const helmet = require('helmet');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');

app.use(helmet());
app.use(morgan('combined'));
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));

Hono ships a growing first-party middleware suite. As of 2026, it covers the common cases:

// Hono — first-party middleware covers the essentials
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { bearerAuth } from 'hono/bearer-auth';
import { cache } from 'hono/cache';
import { compress } from 'hono/compress';
import { csrf } from 'hono/csrf';
import { secureHeaders } from 'hono/secure-headers';

app.use('*', cors({ origin: 'https://yourdomain.com' }));
app.use('*', logger());
app.use('/api/*', bearerAuth({ token: process.env.API_TOKEN! }));

For most new projects, Hono's middleware covers everything you need. The gap narrows as Hono's ecosystem matures. The real risk is if you depend on a specific Express middleware that has no equivalent — for example, a domain-specific authentication library that only provides an Express adapter. Before committing to Hono, verify that your entire middleware dependency chain has equivalents.


Performance

Hono benchmarks at 4-5x faster than Express on Node.js. On Bun, the gap widens further.

FrameworkReq/sLatency (p99)
Hono (Node.js)~350K~2ms
Hono (Bun)~700K+<1ms
Fastify~230K~3ms
Express~80K~8ms

The performance gap has a clear explanation. Express was written using Node.js's callback-based http module and accumulated years of synchronous middleware processing overhead. Hono is async-native throughout, uses the Web Standard Fetch API internally, and has a highly optimized radix trie router. There is simply less work happening per request in Hono.

For the majority of applications, this performance gap does not change production outcomes. Database queries and external API calls dominate response times — moving from 80K to 350K theoretical req/s rarely matters when your database adds 20ms of latency to every request.

Where performance headroom matters: auth services that issue and validate tokens on hot paths, rate-limiting proxies, API gateways, and any service where the framework itself is in the critical path without a slow database behind it.


Package Health

MetricExpressHono
Weekly downloads~35M~1.8M
GitHub stars~65K~22K
Last releaseActive (minor releases)Very active (frequent releases)
TypeScript@types/express (community)Built-in
MaintainedYes, stable cadenceYes, rapid development
Primary contributorsMany (large OSS community)Yusuke Wada + growing community
Runtime supportNode.js onlyNode, Workers, Bun, Deno, Edge

Express is maintained but not innovating. The project is in long-term maintenance mode — bug fixes and security patches ship, but the architecture isn't changing. That's appropriate for a library with 35M weekly users who depend on stability.

Hono is in active development. New middleware, runtime adapters, and DX improvements ship regularly. The community is growing as developers building on edge runtimes and Bun adopt it as their default framework.


When to Choose

Choose Express when:

  • Maintaining an existing Express codebase (don't rewrite stable code)
  • You need a very specific Express middleware with no Hono equivalent
  • Your team only knows Express and learning overhead is a constraint
  • You're building a quick proof-of-concept where familiarity wins

Choose Hono when:

  • Starting any new Node.js backend project in 2026
  • Deploying to Cloudflare Workers, Bun, Deno, or other non-Node.js runtimes
  • TypeScript type safety matters to your team
  • Performance headroom is valuable (high-throughput APIs, auth services)
  • You want built-in Zod validation without boilerplate

For a side-by-side package health view, see the Express vs Hono comparison on PkgPulse. If you're evaluating Hono specifically, the Hono package page tracks its release cadence and download trends. And for a broader look at the framework landscape, the decline of Express and what developers are switching to in 2026 covers the ecosystem shift in detail.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.