Skip to main content

Hono.js in 2026: The Edge Framework That's Replacing Express

·PkgPulse Team

TL;DR

Hono is now the default choice for new Node.js/edge API projects. It runs on every JavaScript runtime with zero code changes, has first-class TypeScript with end-to-end type safety (RPC mode), ships ~14KB, and benchmarks at 3-5x faster than Express. The migration from Express is straightforward — the API is familiar. The edge-first design means Cloudflare Workers, Bun, Vercel Edge, and Deno all work natively. If you're starting a new backend project in 2026 and don't have a specific reason to use Express or Fastify, start with Hono.

Key Takeaways

  • Multi-runtime: same code runs on Node.js, Bun, Deno, Cloudflare Workers, Vercel Edge, AWS Lambda
  • Performance: ~3-5x faster than Express; comparable to Fastify in benchmarks
  • Bundle size: ~14KB total — Express is ~200KB with its common deps
  • TypeScript RPC: hc() client gives end-to-end type safety like tRPC, without the overhead
  • Download growth: 1K/week (2022) → 5M/week (2024) → 20M/week (2026)

Why Hono Won

The JavaScript backend landscape (2026):

Express (2010):
  → 35M weekly downloads (mostly legacy, slow growth)
  → Node.js only
  → CommonJS first, ESM support added later
  → No TypeScript types (DefinitelyTyped separate)
  → ~200KB with common middleware
  → Middleware ecosystem is huge but unmaintained
  → 9+ years between v4 and v5

Fastify (2016):
  → 10M weekly downloads
  → Node.js only (some Bun support)
  → Fast (schema-based serialization)
  → TypeScript support
  → Good for Node.js-only projects

Hono (2022):
  → 20M weekly downloads and growing fast
  → Every JavaScript runtime
  → TypeScript-first from day one
  → Web Standards API (Request/Response)
  → 14KB total
  → RPC mode for type-safe clients
  → Built-in middleware: auth, CORS, rate limit, logger, etc.

The shift happened when:
1. Cloudflare Workers went mainstream (Node.js APIs don't work there)
2. Bun adoption grew (wanted fast + standard)
3. Edge deployment became standard (Vercel Edge, Cloudflare Workers)
4. TypeScript became the default (not an add-on)

Getting Started: Hono vs Express Side by Side

// ─── Express ───
import express from 'express';

const app = express();
app.use(express.json());

app.get('/users/:id', async (req, res) => {
  const user = await getUser(req.params.id);
  if (!user) return res.status(404).json({ error: 'Not found' });
  res.json(user);
});

app.post('/users', async (req, res) => {
  const { name, email } = req.body; // untyped
  const user = await createUser({ name, email });
  res.status(201).json(user);
});

app.listen(3000);

// ─── Hono ───
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 user = await getUser(c.req.param('id'));
  if (!user) return c.json({ error: 'Not found' }, 404);
  return c.json(user);
});

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

export default app;
// Note: no app.listen() — Hono exports a fetch handler
// The runtime (Node.js/Bun/Cloudflare) handles the server

Multi-Runtime: Same Code Everywhere

// One Hono app, multiple deployment targets:

// app.ts (your actual app — same for all runtimes):
import { Hono } from 'hono';

export const app = new Hono()
  .get('/health', (c) => c.json({ status: 'ok' }))
  .get('/users', async (c) => {
    const users = await db.user.findMany();
    return c.json(users);
  });

export type AppType = typeof app;

// ─── Node.js ───
// index.node.ts:
import { serve } from '@hono/node-server';
import { app } from './app';
serve({ fetch: app.fetch, port: 3000 });

// ─── Bun ───
// index.bun.ts:
import { app } from './app';
export default app; // Bun uses default export with .fetch

// ─── Cloudflare Workers ───
// worker.ts:
import { app } from './app';
export default app; // Workers use default export with .fetch

// ─── Vercel Edge ───
// api/[[...route]].ts:
import { handle } from 'hono/vercel';
import { app } from '../../app';
export const GET = handle(app);
export const POST = handle(app);

// ─── AWS Lambda ───
// lambda.ts:
import { handle } from 'hono/aws-lambda';
import { app } from './app';
export const handler = handle(app);

// The same app.ts runs everywhere with a thin adapter layer.
// Move from Node.js to Cloudflare Workers: change 3 lines.

Hono RPC: End-to-End Type Safety

// Hono's RPC feature — type-safe client like tRPC but lighter:

// server/routes/users.ts:
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const UserRoutes = new Hono()
  .get('/:id', async (c) => {
    const user = await getUser(c.req.param('id'));
    return c.json({ user });
  })
  .post('/',
    zValidator('json', z.object({ name: z.string(), email: z.string().email() })),
    async (c) => {
      const data = c.req.valid('json');
      const user = await createUser(data);
      return c.json({ user }, 201);
    }
  );

export type UserRoutesType = typeof UserRoutes;

// server/index.ts:
import { Hono } from 'hono';
const app = new Hono().route('/users', UserRoutes);
export type AppType = typeof app;

// client.ts (frontend or another service):
import { hc } from 'hono/client';
import type { AppType } from './server';

const client = hc<AppType>('http://localhost:3000');

// Fully typed — no manual type declarations:
const response = await client.users[':id'].$get({ param: { id: '123' } });
const { user } = await response.json();
// user: inferred from server return type ✓

const createResponse = await client.users.$post({
  json: { name: 'Alice', email: 'alice@example.com' }
});
// TypeScript validates the request body against the Zod schema ✓
// TypeScript error if wrong body shape ✓

// vs tRPC: no separate router definition, no adapter, lighter setup
// Works with any HTTP client (not just hc — curl, fetch, etc.)

Built-In Middleware

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { rateLimiter } from 'hono/rate-limiter';
import { bearerAuth } from 'hono/bearer-auth';
import { compress } from 'hono/compress';
import { secureHeaders } from 'hono/secure-headers';
import { etag } from 'hono/etag';

const app = new Hono();

// All built in — zero additional dependencies:
app.use('*', logger());
app.use('*', cors({ origin: ['https://myapp.com'] }));
app.use('*', secureHeaders());   // CSP, HSTS, X-Frame-Options, etc.
app.use('*', compress());        // gzip/brotli
app.use('*', etag());            // ETag caching

// Rate limiting:
app.use('/api/*', rateLimiter({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 100,
  keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',
}));

// Auth:
app.use('/admin/*', bearerAuth({ token: process.env.ADMIN_TOKEN! }));

// JWT auth:
import { jwt } from 'hono/jwt';
app.use('/protected/*', jwt({ secret: process.env.JWT_SECRET! }));

// Compare to Express:
// cors → npm install cors
// helmet → npm install helmet (security headers)
// morgan → npm install morgan (logging)
// express-rate-limit → npm install express-rate-limit
// jsonwebtoken → npm install jsonwebtoken
// 5+ packages vs 0 additional packages with Hono

Performance

Benchmark: HTTP requests/second (Node.js 22, M2 MacBook Pro)
Route: GET /users/:id with JSON response

Framework          req/s    p99 latency
─────────────────────────────────────────
Hono               98,200   1.2ms
Fastify            91,400   1.4ms
Express            28,600   4.8ms
Koa                31,200   4.2ms

Cloudflare Workers (edge, same Hono app):
                  120,000+   0.8ms

Why Hono is fast:
→ Web Standards (Request/Response) = no translation layer
→ Trie-based router (O(log n) route matching vs Express's O(n))
→ No legacy CommonJS overhead
→ Small middleware stack — each middleware adds minimal overhead
→ JIT-friendly code patterns

Compare Hono, Express, Fastify, and other Node.js framework download trends at PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.