Skip to main content

Hono vs itty-router vs worktop: Edge Router Comparison 2026

·PkgPulse Team

Hono benchmarks at 402,820 requests/second on Cloudflare Workers. itty-router hits 212,598 ops/sec. worktop reaches 197,345 ops/sec. In practice, all three are so fast that routing overhead is essentially zero — the differences that actually matter are bundle size, TypeScript support, middleware ecosystem, and multi-runtime support. itty-router is 1/4 the size of Hono's smallest bundle. Hono is used by Cloudflare internally for D1, Workers Logs, and customer APIs.

TL;DR

Hono for the vast majority of edge projects — 2M weekly downloads, 9+ runtime support, excellent TypeScript, built-in middleware, and a growing ecosystem. itty-router when bundle size is a hard constraint and you need the absolute minimal footprint for a Cloudflare Worker. worktop for TypeScript-first Workers with a clean, typed API and built-in support for CORS, sessions, and route groups. For new projects, Hono is the default choice.

Key Takeaways

  • Hono: 2M weekly downloads, 23K GitHub stars, <14kB, runs on 9+ runtimes
  • itty-router: 300K weekly downloads, 2.5K stars, AutoRouter is just 1/4 of Hono's smallest bundle
  • worktop: 30K weekly downloads, TypeScript-first, Workers-specific features (sessions, CORS)
  • Hono benchmarks: 402,820 req/s — fastest routing algorithm (RegExpRouter with Trie)
  • itty-router: Chain-based API, additional args propagate to all handlers automatically
  • All three: Zero cold starts (Workers isolate model), Web Standards (Fetch API)
  • Cloudflare uses Hono internally: D1 Studio, Workers dashboard, customer-facing APIs

The Context: Edge Routing

On Cloudflare Workers, every request handler starts with:

// The Worker entry point (Web Standards)
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Route the request
    // Return a Response
  }
};

Routers simplify this pattern — matching URLs, extracting params, applying middleware — without adding meaningful overhead at the edge.

Hono

Package: hono Weekly downloads: 2M GitHub stars: 23K Creator: Yusuke Wada Bundle: <14 kB (smallest preset)

Hono is the most capable edge framework. It's essentially the Express for edge runtimes — familiar API, excellent TypeScript, and support for every modern JavaScript runtime.

Installation

npm install hono
npx create-hono@latest my-app  # Scaffold a new project

Basic Usage

import { Hono } from 'hono';

const app = new Hono<{ Bindings: Env }>();

// Route params
app.get('/users/:id', async (c) => {
  const id = c.req.param('id');
  const user = await c.env.DB
    .prepare('SELECT * FROM users WHERE id = ?')
    .bind(id)
    .first();
  return user ? c.json(user) : c.json({ error: 'Not found' }, 404);
});

// Middleware
app.use('*', async (c, next) => {
  const start = Date.now();
  await next();
  c.header('X-Response-Time', `${Date.now() - start}ms`);
});

export default app;

Built-in Middleware

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

const app = new Hono();

app.use('*', cors({
  origin: ['https://app.example.com'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
}));
app.use('*', logger());
app.use('/api/admin/*', bearerAuth({ token: Bun.env.API_TOKEN }));

Type-Safe Route Groups

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

const userSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
});

export const userRoutes = new Hono<{ Bindings: Env }>()
  .get('/', async (c) => {
    const users = await c.env.DB.prepare('SELECT * FROM users').all();
    return c.json(users.results);
  })
  .post('/', zValidator('json', userSchema), async (c) => {
    const data = c.req.valid('json');
    const { meta } = await c.env.DB
      .prepare('INSERT INTO users (name, email) VALUES (?, ?)')
      .bind(data.name, data.email)
      .run();
    return c.json({ id: meta.last_row_id }, 201);
  })
  .get('/:id', async (c) => {
    const user = await c.env.DB
      .prepare('SELECT * FROM users WHERE id = ?')
      .bind(c.req.param('id'))
      .first();
    return user ? c.json(user) : c.json({ error: 'Not found' }, 404);
  });

// index.ts
const app = new Hono<{ Bindings: Env }>()
  .route('/users', userRoutes)
  .route('/products', productRoutes);

export type AppType = typeof app;  // For Hono RPC client
export default app;

Hono RPC Client

// Client (React, Node.js, anywhere)
import { hc } from 'hono/client';
import type { AppType } from './worker/index';

const client = hc<AppType>('https://my-api.example.com');

// Fully typed — TypeScript knows all routes, params, and response types:
const response = await client.users.$get();
const users = await response.json();  // typed: User[]

const newUser = await client.users.$post({
  json: { name: 'Alice', email: 'alice@example.com' }
});

Multi-Runtime

// The same app.ts runs on all these:
// Cloudflare Workers: export default app
// Deno: Deno.serve(app.fetch)
// Bun: Bun.serve({ fetch: app.fetch })
// Node.js: serve(app)  // @hono/node-server
// Vercel Edge: export const GET = handle(app)
// AWS Lambda: export const handler = handle(app)

itty-router

Package: itty-router Weekly downloads: 300K GitHub stars: 2.5K Creator: Kevin R. Whitley

itty-router is extreme minimalism. AutoRouter — its batteries-included variant — is 1/4 the size of Hono's smallest bundle. For simple Workers where bundle size matters (cold start or edge network), itty-router delivers.

Installation

npm install itty-router

AutoRouter (Batteries-Included)

import { AutoRouter } from 'itty-router';

const router = AutoRouter();

router
  .get('/users', () => [{ id: 1, name: 'Alice' }])  // Auto-serializes to JSON
  .get('/users/:id', ({ id }) => ({ id, name: 'Alice' }))
  .post('/users', async (request) => {
    const body = await request.json();
    return { id: Math.random(), ...body };
  });

export default router;  // Works as a Workers export directly

itty-router's Unique Feature: Auto-Propagating Args

import { Router } from 'itty-router';

const router = Router();

// Additional args (env, ctx) are automatically propagated to all handlers:
router.get('/users', (request, env, ctx) => {
  // env and ctx available without manual wiring
  return env.DB.prepare('SELECT * FROM users').all();
});

router.all('*', () => new Response('Not found', { status: 404 }));

export default {
  fetch: (...args) => router.fetch(...args),
};

No middleware configuration needed — env and ctx flow through automatically.

itty-router Size Advantage

# Bundle sizes (minified + gzipped):
itty-router (AutoRouter): ~1 kB
itty-router (Router):     <500 bytes
Hono (hono/tiny preset):  ~3 kB
Hono (full):              ~14 kB

# When to care:
# Workers free plan has 1 MB script limit
# Smaller bundles = faster cold start in some scenarios
# Most projects: the difference is irrelevant

itty-router Limitations

  • Less TypeScript support than Hono (no automatic route type inference)
  • No built-in middleware (CORS, logger require custom code)
  • No multi-runtime support (Cloudflare Workers primary)
  • Smaller ecosystem and community than Hono

worktop

Package: worktop Weekly downloads: 30K GitHub stars: 1.8K Creator: Luke Edwards Cloudflare-specific: Yes

worktop is a TypeScript-first Workers framework with built-in features for CORS, sessions, and typed route parameters.

Installation

npm install worktop

Basic Usage

import { Router } from 'worktop';
import * as CORS from 'worktop/cors';

const API = new Router();

// CORS middleware
API.add('OPTIONS', '*', CORS.preflight());
API.add('GET', '/users/:id', async (req, res) => {
  const { id } = req.params;  // Typed string

  const user = await getUser(id);
  if (!user) return res.send(404, { message: 'Not found' });

  res.send(200, user);  // Typed: automatically JSON-serializes
});

API.add('POST', '/users', async (req, res) => {
  const body = await req.body.json<{ name: string; email: string }>();
  const user = await createUser(body);
  res.send(201, user);
});

export default {
  fetch: API.run,
};

Typed Route Params

import { Router } from 'worktop';

const router = new Router();

// TypeScript knows req.params.id is a string
router.add('GET', '/items/:id', async (req, res) => {
  const { id } = req.params;  // string
  // ...
});

// Multiple params
router.add('GET', '/org/:orgId/repo/:repoId/commit/:sha', async (req, res) => {
  const { orgId, repoId, sha } = req.params;  // All typed as string
  // ...
});

worktop Limitations

  • Cloudflare Workers specific (not multi-runtime)
  • Smaller community than Hono
  • Less actively maintained (lower release frequency)
  • No equivalent of Hono's middleware ecosystem

Feature Comparison

FeatureHonoitty-routerworktop
Weekly downloads2M300K30K
Bundle size~14kB (full)~1kB (AutoRouter)~5kB
TypeScript supportExcellentGoodExcellent
Multi-runtime9+ runtimesWorkers-focusedWorkers-only
Built-in middlewareYes (cors, logger, auth, etc.)NoCORS, cache
Benchmarks402K req/s213K req/s197K req/s
RPC clientYes (hono/client)NoNo
Route groupingYesPartialNo
Zod integrationYes (@hono/zod-validator)NoNo

When to Use Each

Choose Hono if:

  • You're building anything beyond a simple 5-route Worker
  • TypeScript type safety and IDE support matter
  • You want built-in middleware (CORS, auth, logging, rate limiting)
  • Your Worker might need to run on multiple runtimes (Deno, Bun, Vercel)
  • You need Hono's RPC client for type-safe client code

Choose itty-router if:

  • Bundle size is a hard constraint
  • Your Worker has 2-5 routes and minimal middleware needs
  • You want the absolute simplest routing API

Choose worktop if:

  • You want Cloudflare-specific typed session and request body helpers
  • TypeScript route params typing is important
  • You were already using worktop and don't need to migrate

The 2026 Recommendation

Hono is the clear choice for new projects. Its 2M weekly downloads and Cloudflare's internal adoption (D1, Workers Logs) are strong signals of production readiness. The multi-runtime support means your code isn't locked to Workers — you can run it locally on Bun or Node.js without changes.

itty-router remains valuable for extremely simple Workers where every byte counts. worktop serves its existing users well but isn't the right starting point in 2026.

Compare edge framework downloads on PkgPulse.

Comments

Stay Updated

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