Hono is a small, fast, type-safe web framework that runs anywhere JavaScript runs: Node, Bun, Deno, Cloudflare Workers, Vercel, Lambda, you name it. Express is stuck on Node and stuck in 2014.
See the case → Show me codeSix reasons teams are leaving Express behind.
Hono uses the standard Request and Response objects, the same ones browsers and Workers use. Express invented its own non-standard req and res twelve years ago.
One codebase, every runtime. Node, Bun, Deno, Cloudflare Workers, AWS Lambda, Vercel, Netlify, Fastly. Express is Node only.
Routes, params, JSON bodies, and middleware are end-to-end typed. With the RPC client you get type safety from server to client without code generation.
The RegExpRouter resolves routes in linear time. Benchmarks consistently put Hono multiples ahead of Express on raw throughput.
JWT, JWK, CORS, ETag, basic auth, bearer auth, JSX renderer, validators, streaming, server-sent events. All first party, all tree-shakeable.
Express 5 took nearly a decade to ship. Hono ships meaningful releases every few weeks with a healthy contributor base.
A quick scan of where each one lands.
| Feature | Hono | Express |
|---|---|---|
| Bundle size | ~14kB gzipped tiny | ~570kB installed heavy |
| Runtime support | Node, Bun, Deno, Workers, Lambda, Vercel universal | Node only locked in |
| TypeScript | Native, end-to-end typed first class | Community @types, partial bolt-on |
| Web standard Request and Response | Yes standards | No, custom req and res proprietary |
| Async middleware | Native async and await clean | Callbacks plus next() legacy |
| Validation | Built in with Zod, Valibot, ArkType included | Bring your own manual |
| JSX server rendering | Built in included | Pick a template engine extra |
| Type-safe RPC client | Yes, hc() included | No missing |
| Release cadence | Frequent active | Express 5 took nine years slow |
A typed, validated JSON endpoint in both frameworks.
import { Hono } from 'hono' import { zValidator } from '@hono/zod-validator' import { z } from 'zod' const app = new Hono() const schema = z.object({ name: z.string().min(1) }) app.post( '/hello', zValidator('json', schema), (c) => c.json({ msg: `hi ${c.req.valid('json').name}` }) ) export default app
const express = require('express') const { z } = require('zod') const app = express() app.use(express.json()) const schema = z.object({ name: z.string().min(1) }) app.post('/hello', (req, res) => { const parsed = schema.safeParse(req.body) if (!parsed.success) return res.status(400).json(parsed.error) res.json({ msg: `hi ${parsed.data.name}` }) }) app.listen(3000)
Express was the right answer for Node in 2010. Hono is the right answer for everything that runs JavaScript today. Smaller, faster, typed, and portable. If you are starting something new, you almost certainly want Hono.