Web Development · Backend Frameworks
Hono in 2026: The Web Framework Built for the Edge
Hono started as a tiny router for Cloudflare Workers and grew into the default choice for edge APIs. Here is what it does well, where it fits, and why the 'runs everywhere' claim is actually true.
Anurag Verma
7 min read
Sponsored
When Cloudflare Workers first became mainstream, the available framework options were thin. Express didn’t work because it depended on Node.js APIs. Fastify had the same problem. You were writing routing logic by hand, matching path strings with regex and tediously parsing request bodies.
Hono came out of that constraint. It was built from scratch to run in V8-based runtimes without any Node.js dependencies. In 2026, it runs on Cloudflare Workers, Deno Deploy, Bun, Node.js, Vercel Edge Functions, AWS Lambda, Netlify Edge Functions, and the browser. The same application code works across all of them with minimal configuration changes.
That’s a real claim. Here’s what it actually means in practice.
The Core API
Hono’s routing API will be immediately familiar if you’ve used Express or Fastify:
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
app.get('/users/:id', async (c) => {
const id = c.req.param('id')
const user = await db.users.findOne(id)
if (!user) return c.json({ error: 'Not found' }, 404)
return c.json(user)
})
app.post('/users', async (c) => {
const body = await c.req.json()
const user = await db.users.create(body)
return c.json(user, 201)
})
export default app
The context object c is the main interface. It provides request parsing, response helpers, cookies, headers, and environment access. The API is small enough to learn in an hour.
The runtime-specific entry points look like this:
// Cloudflare Workers — export default is enough
export default app
// Node.js
import { serve } from '@hono/node-server'
serve(app)
// Bun
Bun.serve(app)
// Deno
Deno.serve(app.fetch)
The app.fetch method is a standard Request => Response function — the same interface used by all edge runtimes. That’s the portability mechanism.
Middleware
Hono ships built-in middleware for the things you need on every API:
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { prettyJSON } from 'hono/pretty-json'
import { bearerAuth } from 'hono/bearer-auth'
const app = new Hono()
// Apply globally
app.use('*', logger())
app.use('*', cors({
origin: ['https://app.example.com'],
allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
}))
// Apply to specific routes
app.use('/api/*', bearerAuth({ token: process.env.API_TOKEN }))
app.use('/api/*', prettyJSON())
The built-in list covers: logger, CORS, bearer auth, basic auth, JWT, compress, ETag, cache, rate limiting, CSRF, body limit, and several more. Most small-to-medium APIs don’t need third-party middleware packages.
Custom middleware follows the same pattern as any middleware system:
app.use('/admin/*', async (c, next) => {
const token = c.req.header('Authorization')?.replace('Bearer ', '')
if (!token) return c.json({ error: 'Unauthorized' }, 401)
try {
const payload = await verifyJWT(token, c.env.JWT_SECRET)
c.set('userId', payload.sub)
await next()
} catch {
return c.json({ error: 'Invalid token' }, 401)
}
})
// Downstream handlers can read from context
app.get('/admin/dashboard', (c) => {
const userId = c.get('userId')
return c.json({ userId, dashboard: '...' })
})
TypeScript Support
Hono’s TypeScript integration is well-designed. You can define environment bindings (for Cloudflare Workers), variables, and custom context values with full type safety:
type Bindings = {
DATABASE_URL: string
JWT_SECRET: string
KV_STORE: KVNamespace // Cloudflare KV type
}
type Variables = {
userId: string
}
const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()
app.use('/protected/*', async (c, next) => {
// c.env.DATABASE_URL is typed as string
// c.env.KV_STORE is typed as KVNamespace
c.set('userId', 'user_123') // type-checked
await next()
})
app.get('/protected/profile', (c) => {
const userId = c.get('userId') // typed as string
return c.json({ userId })
})
RPC is where the TypeScript goes furthest. Hono can generate a fully-typed client from your route definitions:
// server.ts
const routes = app
.get('/users/:id', (c) => {
return c.json({ id: c.req.param('id'), name: 'Alice' })
})
.post('/users', async (c) => {
const body = await c.req.json<{ name: string }>()
return c.json({ id: 'new', ...body }, 201)
})
export type AppType = typeof routes
// client.ts
import { hc } from 'hono/client'
import type { AppType } from './server'
const client = hc<AppType>('https://api.example.com')
// Fully typed — parameter names, response shapes, everything
const user = await client.users[':id'].$get({ param: { id: '123' } })
const json = await user.json()
// json is typed as { id: string, name: string }
The RPC client is the closest thing in the JavaScript ecosystem to tRPC without requiring a specific framework. If your frontend and backend are in the same repo, this removes almost all manual type duplication.
Routing
Hono supports grouped routes, which makes larger APIs manageable:
import { Hono } from 'hono'
const api = new Hono().basePath('/api')
const users = new Hono()
users.get('/', (c) => c.json({ users: [] }))
users.get('/:id', (c) => c.json({ id: c.req.param('id') }))
users.post('/', async (c) => c.json(await c.req.json(), 201))
const products = new Hono()
products.get('/', (c) => c.json({ products: [] }))
products.post('/', async (c) => c.json(await c.req.json(), 201))
api.route('/users', users)
api.route('/products', products)
export default api
This keeps each resource in its own file and composes cleanly. The router is a trie-based implementation, which keeps performance predictable as route counts grow.
Performance
Hono is fast. On Cloudflare Workers, where cold start time matters, it adds essentially no overhead. The bundle size is around 14KB (uncompressed) for the core, which matters on edge runtimes where bundle size affects startup time.
The benchmark comparisons are Hono’s homepage selling point, and the numbers are real for edge runtimes. On Node.js, the differences between Hono and Fastify or Elysia are smaller and mostly irrelevant for typical API workloads. The performance case for Hono on Node.js is about consistency with your edge deployments, not about raw throughput.
When Hono Is the Right Choice
Building a Cloudflare Workers API. This is the original use case and still the strongest one. Hono was designed for Workers and the integration is frictionless. Environment bindings, Durable Objects, KV, R2, D1 — all work naturally through the context.
An edge-deployed backend that needs to run locally too. If you’re deploying to Vercel Edge Functions or Netlify Edge, Hono’s portability means your local dev server runs the same code without emulation layers.
An API that needs to be small and dependency-light. Serverless cold starts are sensitive to bundle size. A Hono API with a few middleware packages is far smaller than an equivalent Express/Fastify setup with the same ecosystem dependencies.
A team already using TypeScript that wants end-to-end type safety. The RPC client pairs well with React apps and makes type-safe API calls without code generation steps.
Where It Doesn’t Fit
For a conventional Node.js server-rendered app (not edge), Hono’s advantages are less clear. Fastify is faster on raw Node.js benchmarks, has a larger plugin ecosystem, and has more production track record on that runtime. Neither is a strong argument against Hono, but if your stack is firmly Node.js, the “runs everywhere” advantage doesn’t apply.
For apps that need heavy request processing — file parsing, streaming, complex multipart handling — Hono’s streaming support exists but is less developed than mature Node.js frameworks. These are fixable gaps, not architectural limitations.
Getting Started
# Cloudflare Workers
npm create cloudflare@latest my-api -- --template hono
# Node.js
npm create hono@latest my-api
# Select Node.js runtime
# Bun
bun create hono my-api
The scaffold includes the runtime-specific entry point, basic routing, and TypeScript configuration. From there, it’s just adding routes.
Hono filled a specific gap — a fast, minimal, TypeScript-first router that didn’t need Node.js — and it filled it well. In 2026 the edge runtime ecosystem has matured significantly, and Hono is the default framework choice for anything running outside a traditional Node.js server.
Sponsored
More from this category
More from Web Development
OAuth 2.0 and PKCE: The Web Auth Patterns Every SPA Developer Needs in 2026
Technical SEO for JavaScript Apps in 2026: What Google Actually Renders
Progressive Web Apps in 2026: What Actually Works on iOS and Android
Sponsored
The dispatch
Working notes from
the studio.
A short letter twice a month — what we shipped, what broke, and the AI tools earning their keep.
Discussion
Join the conversation.
Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.
Sponsored