itty-router
An ultra-tiny (~1kB), zero-dependency TypeScript router built for Cloudflare Workers and other serverless/edge runtimes.
Repository Health
Technical Analysis
itty-router is a microrouter designed around a single constraint: size. Where routers like Express weigh in at hundreds of kilobytes, itty-router’s most minimal build (IttyRouter) starts at roughly 450 bytes, with the batteries-included AutoRouter variant landing around 970 bytes — small enough that bundle size stops being a tax on every request in a Cloudflare Worker, Deno Deploy function, or other cold-start-sensitive environment.
Under the hood it uses a Proxy to turn any HTTP verb into a chainable route-registration method (router.get(...), router.post(...), arbitrary custom methods included), compiling each route pattern into a named-capture regex at registration time. Dispatch is a single fetch(request) call that walks the compiled routes, matches the pathname, and threads params and parsed query-string values onto the request object before invoking handlers in order.
AutoRouter builds on the lower-level Router primitive to add a full middleware lifecycle — before hooks, a catch handler for centralized error formatting, and finally hooks for response post-processing (including automatic JSON formatting and a 404 fallback) — giving Express-like ergonomics without Express-like weight. The package also ships companion utilities for CORS handling, cookie/content parsing middleware, typed response helpers (json, text, html, image formats), and a StatusError class for throwing HTTP errors directly from route handlers.
Because it operates entirely on the standard Fetch API Request/Response objects, it works unmodified across Cloudflare Workers, Deno, Bun, Node (18+), and the browser — anywhere the Fetch API is available.
What You Get
- IttyRouter — the smallest possible router: route registration via Proxy-based verb methods and regex-based path matching, with no built-in middleware lifecycle.
- Router — adds
before,catch, andfinallyhook arrays around route dispatch for a full middleware/error-handling lifecycle. - AutoRouter — a batteries-included
Routerpreconfigured with automatic JSON response formatting, a default 404 handler, and centralized error formatting out of the box. - Route and query parsing — named params (
:id), greedy params (:path+), and wildcards (*) compiled to regex at registration time; query strings parsed into arequest.queryobject automatically. - Response helpers —
json,text,html,jpeg,png,webp, andstatusformatters for returning typedResponseobjects with one call. - CORS utilities — a
cors()factory producingpreflightandcorsifyfunctions to handle OPTIONS requests and append CORS headers to any response. - Error handling — a
StatusErrorclass anderror()formatter that convert thrown errors (or explicit status codes) into properly-shaped JSON error responses. - Middleware add-ons —
withParams,withCookies, andwithContentfor binding proxy-based request enhancements without extra dependencies.
Common Use Cases
- Building lightweight REST APIs on Cloudflare Workers where every extra kilobyte adds to cold-start time and Worker size limits.
- Serverless functions (Deno Deploy, Bun, edge middleware) that need routing without pulling in a full Node.js-oriented framework.
- Prototyping APIs quickly with
AutoRouter’s zero-config JSON formatting, 404 handling, and error catching. - APIs that need CORS support without a separate middleware package — using the built-in
cors()helper alongside route handlers. - Projects that want Express-like route/method chaining (
router.get().post()) but need to stay under strict bundle-size budgets.
Under The Hood
Architecture
The core of both IttyRouter and Router is a Proxy wrapped around an empty object: its get trap intercepts any property access (router.get, router.post, router.anything) and returns a function that compiles the given path into a named-capture regex — via a compact chain of .replace() calls handling greedy params (:name+), named params (:name), literal dots, and wildcards (*) — then pushes a [method, regex, handlers, path] tuple onto a shared routes array. Dispatch is a single fetch(request, ...args) method that parses the query string into request.query, then walks routes matching method and pathname against each compiled regex in registration order, invoking handlers until one returns a non-null response. Router layers a full middleware lifecycle on top of this — before hooks run first (can short-circuit), route handlers run inside a try/catch that defers to a user-supplied catch handler, and finally hooks post-process the response (this is where AutoRouter injects automatic JSON formatting and a default 404 responder). The design means changing the core route-matching regex logic in one small block would ripple through every router variant and every published sub-package, since they all consume the same routes array shape.
Tech Stack
Written entirely in TypeScript with zero runtime dependencies, compiled to a hybrid ESM/CJS distribution (itty-packager, the maintainer’s own build/lint/release CLI, drives bun run build/lint/release). Tests run under Bun’s built-in test runner (bun test --coverage), with coverage reported to Coveralls via GitHub Actions across separate test, lint, and tag-triggered release workflows. The package has no framework, ORM, or database dependency by design — it operates purely on standard Fetch API Request/Response objects, which is what lets it run unmodified on Cloudflare Workers, Deno, Bun, Node 18+, and browsers.
Code Quality
The src/ directory pairs almost every implementation file with a co-located *.spec.ts test file (11 spec files against roughly a dozen source modules), and the project advertises 100% coverage tracked continuously via Coveralls, enforced on every push and pull request through GitHub Actions. Error handling is explicit and typed: a dedicated StatusError class carries an HTTP status plus arbitrary metadata, and a single error() formatter normalizes thrown errors, StatusError instances, or raw status codes into consistent JSON error bodies. Naming is consistent (PascalCase router factories, camelCase helpers and middleware), and linting runs through a shared config pulled from the maintainer’s itty-packager package. The codebase does lean on @ts-ignore/@ts-expect-error in a handful of spots to work around the dynamic Proxy-based API surface — a deliberate tradeoff of type-checker friction for bundle size and API ergonomics.
What Makes It Unique
Most routers (Express, Koa, even most “micro” alternatives) build their route tables as arrays or tries walked by conventional loops with substantial supporting infrastructure. itty-router instead compiles routes into named-capture regexes at registration time and uses a single Proxy get trap to make every HTTP verb a chainable method with no per-verb code — collapsing what is normally hundreds of lines of dispatch logic into a few dozen. Combined with the before/catch/finally middleware model in Router, this gives close to Express-level ergonomics while keeping the smallest configuration under a kilobyte, which is a genuinely distinctive tradeoff for cold-start-sensitive serverless and edge environments rather than a generic feature checklist.
Used by 3 apps in this directory
Helicone
Monitoring · AI Development · Analytics
An open-source AI gateway and LLM observability platform that routes requests to 100+ models while logging cost, latency, and full traces for every call.
GraphQL Hive
Developer Tools · Devops · Monitoring
Open-source GraphQL schema registry and observability platform with breaking change detection, federation support, and CI/CD integration for teams of any size.
Supabase
Developer Tools · Databases · Search
The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.