# blade47/hono Wiki
## Overview
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/overview
Relevant source files
The following files were used as context for generating this wiki page:
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/adapter/lambda-edge/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/lambda-edge/handler.ts)
Hono is a high-performance, lightweight web framework designed for edge-native environments, though it maintains compatibility across standard Node.js and serverless environments. Its architecture is built around the `Hono` class (aliased as `HonoBase` within its own module), which provides a router-agnostic foundation for defining routes, middleware, and request-handling pipelines. This design separation allows Hono to be modular: the framework core is decoupled from the router implementation and the runtime-specific adapter.
The system centers on the `Context` object, which provides an abstraction over the native `Request` and `Response` objects. By wrapping these in a specialized container, Hono enables efficient propagation of environment variables, request state, and execution context. This architecture resolves the primary problem of fragmented web standard support in different cloud runtimes by providing a unified, TypeScript-first API that behaves consistently whether running on Cloudflare Workers, AWS Lambda, or local environments.
The framework's operation is structured into a pipeline: a request enters via an adapter's `handle` or `fetch` method, is routed using a pluggable `Router` (e.g., `SmartRouter`, `RegExpRouter`), and is executed through a sequence of middleware and handlers orchestrated by a composition engine. By avoiding heavy dependencies and prioritizing a clean, composable design, Hono provides a "build-to-fit" experience for high-traffic, low-latency applications.
## Core Framework Architecture
The framework is managed via the `Hono` class, which manages route registration, error handling, and the lifecycle of the incoming HTTP request. Unlike typical frameworks, this class does not contain a hardcoded router; it is an implementation that relies on an injected `Router` instance provided at initialization or via specific class extensions.
When a request is received, `fetch()` serves as the primary entry point, performing the following:
1. Resolves the path using the configured `getPath` function (defaulting to a standard URL parser).
2. Executes a route match against the `router` property, which returns a `matchResult` containing candidate handlers.
3. Instantiates a `Context` object that holds the `Request`, `env` (bindings), and `matchResult`.
4. If multiple handlers are present, it uses a `compose` function to execute them sequentially, passing `c` (Context) and `next()` through the pipeline.
Sources: [src/hono-base.ts:98-124](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L98-L124), [src/hono-base.ts:479-485](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L479-L485)
## Context Abstraction
The `Context` class is the primary interface for handlers to interact with an incoming request and craft a response. It encapsulates the underlying `Request` object and offers a typed API for setting response headers, JSON bodies, or HTML.
Internal state tracking includes the `finalized` boolean. When a handler completes its logic, setting a response via `res` or other helper methods often triggers a transition to `finalized = true`. This state invariant prevents further modification to the response once it is in the process of being committed to the network, ensuring the integrity of the response lifecycle.
> [!TIP]
> Use `c.set()` and `c.get()` to pass data between middleware. These variables are managed internally by a `Map` instance within the `Context` and are scoped strictly to the current request lifecycle.
Sources: [src/context.ts:293-301](https://github.com/blade47/hono/blob/main/src/context.ts#L293-L301), [src/context.ts:317-317](https://github.com/blade47/hono/blob/main/src/context.ts#L317-L317), [src/context.ts:546-556](https://github.com/blade47/hono/blob/main/src/context.ts#L546-L556)
## Request Routing and Dispatch
Hono utilizes a pluggable routing mechanism. The constructor allows injecting different routers through the `options.router` field. The `SmartRouter` (used by default) acts as an aggregator, choosing the most efficient router implementation based on the registration of routes.
The flow for adding a route involves:
1. Identifying the method and path (merged with the current `basePath`).
2. The router's `add()` method is invoked, storing the handler and route metadata.
When dispatching, Hono matches the request URL path to the stored route. If multiple routes overlap, the specific order of matching is determined by the `Router`'s internal implementation.
```mermaid
flowchart TD
A[Request] --> B{Router.match}
B -->|Found| C[Create Context]
C --> D[Compose Middleware]
D --> E[Handler Execution]
E --> F[Finalized Response]
```
Sources: [src/hono-base.ts:385-397](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L385-L397), [src/hono-base.ts:419-427](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L419-L427), [src/hono.ts:26-33](https://github.com/blade47/hono/blob/main/src/hono.ts#L26-L33)
## Adapter Mechanism
Hono is platform-agnostic, achieving this via adapters found in `src/adapter/`. These adapters translate platform-specific request objects (e.g., AWS Lambda's events or Cloudflare's `EventContext`) into a standard `Request` object that Hono's `.fetch()` can process.
The `aws-lambda` adapter uses specialized processor logic (such as `ALBProcessor` or `EventV1Processor`). Each processor implements a standard interface for extracting the method, path, and headers, allowing Hono to handle different AWS trigger types uniformly.
| Adapter | Responsibility | Primary Data Mapping |
| :--- | :--- | :--- |
| `aws-lambda` | Event translation | Maps event headers/body to `Headers` and `Request`. |
| `cloudflare-pages` | Middleware orchestration | Injects `EventContext` into the Hono environment. |
| `lambda-edge` | CloudFront event mapping | Converts CloudFront event structure to `Headers`. |
Sources: [src/adapter/aws-lambda/handler.ts:278-317](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L278-L317), [src/adapter/cloudflare-pages/handler.ts:32-46](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts#L32-L46)
## Error Handling
Hono implements a catch-all mechanism for runtime exceptions. The default `errorHandler` is defined in `HonoBase` to provide a fallback: it logs the error to the console and returns a generic "Internal Server Error" (500) response.
Custom error handlers can be registered via the instance's `onError` property or method assignment. If a handler throws an `HTTPException` (which carries an embedded response), the framework unwraps and returns that response directly rather than defaulting to 500.
> [!WARNING]
> Always return a Response from your error handler. If the error handler throws an exception, the framework execution will bubble that error to the underlying runtime adapter, likely resulting in a non-HTTP compliant failure.
Sources: [src/hono-base.ts:35-42](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L35-L42), [src/hono-base.ts:271-274](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L271-L274)
## Worked Example: Defining a Route
The following code demonstrates defining a simple JSON endpoint exercising the Hono lifecycle.
```typescript
import { Hono } from 'hono';
const app = new Hono();
// Route registration
app.get('/api/message', (c) => {
// Set custom header
c.header('X-Hono-Custom', 'Value');
// Return JSON response
return c.json({ message: 'Hello, world!' });
});
```
Sources: [src/hono.ts:16-34](https://github.com/blade47/hono/blob/main/src/hono.ts#L16-L34), [src/context.ts:708-721](https://github.com/blade47/hono/blob/main/src/context.ts#L708-L721)
## Design Trade-offs
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Router-agnostic core | Flexibility to swap routers and adapters. | Slightly higher complexity for framework developers. |
| `Context` encapsulation | Consistent API across disparate runtimes. | Minor allocation overhead for every request. |
| Middleware composition | Simple, linear control flow of `next()`. | Recursion depth limits in extremely long pipelines. |
Sources: [src/hono-base.ts:98-103](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L98-L103), [src/context.ts:293-299](https://github.com/blade47/hono/blob/main/src/context.ts#L293-L299), [src/compose.ts](https://github.com/blade47/hono/blob/main/src/compose.ts)
## Related
- [[Quick Start]]
- [[Project Structure]]
- [[Application Routing]]
---
## Quick Start
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/quick-start
Relevant source files
The following files were used as context for generating this wiki page:
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts)
- [src/adapter/lambda-edge/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/lambda-edge/handler.ts)
- [src/helper/proxy/index.ts](https://github.com/blade47/hono/blob/main/src/helper/proxy/index.ts)
- [src/preset/tiny.ts](https://github.com/blade47/hono/blob/main/src/preset/tiny.ts)
- [src/index.ts](https://github.com/blade47/hono/blob/main/src/index.ts)
- [runtime-tests/workerd/index.ts](https://github.com/blade47/hono/blob/main/runtime-tests/workerd/index.ts)
- [src/adapter/vercel/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/vercel/handler.ts)
- [src/adapter/netlify/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/netlify/handler.ts)
- [src/helper/dev/index.ts](https://github.com/blade47/hono/blob/main/src/helper/dev/index.ts)
- [src/router/linear-router/index.ts](https://github.com/blade47/hono/blob/main/src/router/linear-router/index.ts)
- [src/adapter/cloudflare-pages/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/index.ts)
- [src/adapter/vercel/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/vercel/index.ts)
- [src/adapter/service-worker/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/service-worker/index.ts)
- [src/router/smart-router/index.ts](https://github.com/blade47/hono/blob/main/src/router/smart-router/index.ts)
- [src/adapter/deno/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/deno/index.ts)
- [src/adapter/cloudflare-workers/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-workers/index.ts)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/adapter/aws-lambda/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/index.ts)
- [src/adapter/lambda-edge/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/lambda-edge/index.ts)
- [src/router/pattern-router/index.ts](https://github.com/blade47/hono/blob/main/src/router/pattern-router/index.ts)
- [src/helper/testing/index.ts](https://github.com/blade47/hono/blob/main/src/helper/testing/index.ts)
- [src/adapter/service-worker/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/service-worker/handler.ts)
- [src/adapter/bun/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/bun/index.ts)
- [src/adapter/netlify/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/netlify/index.ts)
Hono is a web framework built fundamentally on Web Standards, designed for environments like Cloudflare Workers, Deno, Bun, and traditional Node.js/Lambda runtimes. The "Quick Start" capabilities reflect the framework's core design philosophy: to provide a lightweight, high-performance router and execution context that remains agnostic to the underlying platform.
The system achieves this by decoupling the core router implementation from the request handling logic. The `Hono` class provides the common interface for routing and middleware, while different presets allow developers to trade off binary size against routing complexity.
When starting a project, a developer interacts with the `Hono` instance, which serves as the entry point. The framework maps HTTP methods to internal route tables and provides a standardized `Context` object that encapsulates the environment, request, and lifecycle methods, ensuring that code remains portable across disparate edge and serverless providers.
## Core Initialization Mechanics
At the heart of the system, initialization occurs by constructing an `Hono` instance. The constructor accepts an optional configuration object, which allows for defining the routing strategy, strict path matching, and path normalization logic.
```typescript
// Example: Standard Quick Start initialization
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono!'))
export default app
```
Sources: [src/index.ts:6-14](https://github.com/blade47/hono/blob/main/src/index.ts#L6-L14)
The constructor delegates to the `Hono` class, which handles the registration of HTTP methods (GET, POST, etc.) into an internal routing table using internal registration methods that populate the router.
> [!NOTE]
> The `Hono` class is the primary interface. It initializes with a default router (e.g., `SmartRouter`), while specific preset files inject different routing implementations to optimize for performance or bundle size.
Sources: [src/hono.ts:26-34](https://github.com/blade47/hono/blob/main/src/hono.ts#L26-L34), [src/preset/tiny.ts:16-20](https://github.com/blade47/hono/blob/main/src/preset/tiny.ts#L16-L20)
## Routing Architecture
Routing is the core mechanism that determines how an incoming `Request` object maps to a `Handler`. Hono utilizes a routing system based on registered patterns.
| Router Type | Implementation File | Strategy |
| :--- | :--- | :--- |
| `SmartRouter` | `src/router/smart-router/` | Adaptive; delegates to other routers based on pattern complexity. |
| `RegExpRouter` | `src/router/reg-exp-router/` | Uses regular expressions for matching dynamic paths. |
| `TrieRouter` | `src/router/trie-router/` | Uses a trie data structure for performant prefix matching. |
| `PatternRouter` | `src/router/pattern-router/` | Optimized for small, simple route definitions. |
| `LinearRouter` | `src/router/linear-router/` | Simple linear search; efficient for very few routes. |
Sources: [src/hono.ts:3-5](https://github.com/blade47/hono/blob/main/src/hono.ts#L3-L5), [src/preset/quick.ts:8-10](https://github.com/blade47/hono/blob/main/src/preset/quick.ts#L8-L10)
The routing mechanism is triggered when a request is dispatched, which takes a request and environment variables, retrieves the path, and performs a lookup to match the method and path against the internal router's index.
Sources: [src/hono-base.ts:418-419](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L418-L419)
## The Request Dispatch Flow
When a request arrives, the `fetch` method serves as the entry point. The following chain shows how the request is processed:
1. `fetch()` → Entry point; receives the raw `Request` and environment objects.
2. `dispatch` logic → Prepares the `Context` and performs route matching.
3. `router.match()` → Performs lookups to find eligible handlers.
4. `compose()` → Executes the middleware and handler stack if more than one handler is registered.
If a single handler is found, the dispatch path avoids `compose` to optimize performance, calling the handler directly and resolving its promise.
```mermaid
flowchart TD
A[fetch] --> B["dispatch logic"]
B --> C["router.match"]
C --> D{Single
Handler?}
D -- Yes --> E["Direct Execute"]
D -- No --> F["compose(handlers)"]
E --> G[Context Finalized]
F --> G
```
Sources: [src/hono-base.ts:429-450](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L429-L450)
## The Context Object (`Context`)
The `Context` object is a load-bearing structure. It is created per-request and provides the interface through which developers interact with the request data and define the response.
Key components of `Context`:
- `env`: The environment-specific bindings (e.g., KV, D1, or environment variables).
- `req`: A wrapper around the native `Request` providing helper methods.
- `res`: The response container. When set, it marks the context as `finalized`.
- `set()` / `get()`: A shared storage mechanism for variables across middleware layers.
> [!IMPORTANT]
> The `Context` object handles the logic of finalizing the response. If the `finalized` flag is false after the middleware stack completes, the framework throws an error to ensure that the developer has provided a valid response object.
Sources: [src/context.ts:300-345](https://github.com/blade47/hono/blob/main/src/context.ts#L300-L345), [src/hono-base.ts:455-459](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L455-L459)
## Adapter Logic
Hono is built to run everywhere. The adapter pattern bridges the gap between different cloud runtime event structures (like AWS API Gateway, Cloudflare Pages, or Vercel functions) and the internal `Hono.fetch` method.
| Adapter | Primary Entry Point | Strategy |
| :--- | :--- | :--- |
| `aws-lambda` | `handle()` | Converts Lambda event structures (APIGateway, ALB) to Request. |
| `cloudflare-pages` | `handle()` | Maps `EventContext` properties to the `hono` lifecycle. |
| `lambda-edge` | `handle()` | Translates `CloudFrontRequest` for CloudFront edge events. |
| `bun` | `getBunServer()` | Native integration for Bun's HTTP server. |
Sources: [src/adapter/aws-lambda/handler.ts:239-252](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L239-L252), [src/adapter/cloudflare-pages/handler.ts:32-46](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts#L32-L46)
Each adapter implements its own handling logic. For instance, the `aws-lambda` adapter includes logic for determining if a response should be base64-encoded, which is a common requirement in API Gateway event handling.
## Development and Testing
The system includes robust helpers for development and testing. `showRoutes` provides an observability tool to inspect the route table, while `testClient` allows developers to test their applications without performing network-level I/O.
```typescript
// Example: Testing with testClient
import { Hono } from 'hono'
import { testClient } from 'hono/testing'
const app = new Hono()
app.get('/test', (c) => c.json({ data: 'ok' }))
const client = testClient(app)
const res = await client.test.$get()
const data = await res.json() // { data: 'ok' }
```
Sources: [src/helper/testing/index.ts:16-27](https://github.com/blade47/hono/blob/main/src/helper/testing/index.ts#L16-L27)
`testClient` works by injecting a custom `fetch` function that points directly to the `app.request` internal method, bypassing the need for an actual server.
Sources: [src/helper/testing/index.ts:22-24](https://github.com/blade47/hono/blob/main/src/helper/testing/index.ts#L22-L24)
## Related
- [[Overview]]
- [[Project Structure]]
---
## Project Structure
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/project-structure
Relevant source files
The following files were used as context for generating this wiki page:
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts)
- [src/jsx/hooks/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/hooks/index.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/jsx/context.ts](https://github.com/blade47/hono/blob/main/src/jsx/context.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/helper/ssg/ssg.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/ssg.ts)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/jsx/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/index.ts)
- [vitest.config.ts](https://github.com/blade47/hono/blob/main/vitest.config.ts)
- [src/middleware/language/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/language/index.ts)
- [src/adapter/cloudflare-pages/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/index.ts)
- [src/router.ts](https://github.com/blade47/hono/blob/main/src/router.ts)
- [src/helper/factory/index.ts](https://github.com/blade47/hono/blob/main/src/helper/factory/index.ts)
- [src/middleware/jwt/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jwt/index.ts)
- [src/adapter/netlify/mod.ts](https://github.com/blade47/hono/blob/main/src/adapter/netlify/mod.ts)
- [src/helper/ssg/index.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/index.ts)
- [src/adapter/netlify/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/netlify/index.ts)
- [src/jsx/dom/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/index.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
Hono is architected as a lightweight, modular web framework that prioritizes web standards. The project structure is carefully designed to facilitate multi-platform compatibility, including runtimes like Node.js, Bun, Deno, Cloudflare Workers, and serverless environments. By keeping the core logic decoupled from environment-specific APIs, Hono ensures consistent behavior across these diverse deployment targets while remaining highly performant.
The hierarchy is organized into specific domain folders: `src/` serves as the primary root containing the core logic, which is further sub-divided into functional subsystems like `jsx/` for templating, `middleware/` for request/response processing, `helper/` for utility operations, and `adapter/` for platform-specific glue code. This modularity allows for tree-shaking and efficient code distribution, enabling users to import only the components they require.
This wiki details the internal structure and organization of these components, tracing how Hono wires together its routing engine, rendering pipeline, and middleware chains to deliver a unified interface across different environments.
## Core Package Configuration
The project is configured via `package.json` and `jsr.json`. These files define the external API surface area, controlling how the library is exported to consumers. By utilizing granular `exports` fields, the framework allows developers to import specific sub-packages (e.g., `hono/jsx`, `hono/jwt`, `hono/adapter/cloudflare-pages`), reducing the bundle size significantly.
| Configuration File | Primary Purpose |
| :--- | :--- |
| `package.json` | Project metadata, build scripts, and ESM/CJS exports mapping. |
| `jsr.json` | Configuration for JSR registry, defining public modules and export paths. |
Sources: [package.json:1-701](https://github.com/blade47/hono/blob/main/package.json#L1-L701), [jsr.json:1-111](https://github.com/blade47/hono/blob/main/jsr.json#L1-L111)
## Adapter Architecture
Adapters act as the translation layer between Hono's `fetch`-compliant core and the native request/response objects provided by specific platforms. Each adapter lives in `src/adapter/` and provides a standard interface (typically a `handle` function) that transforms platform-specific events into a standard `Request` object.
> [!NOTE]
> The Cloudflare Pages adapter provides both a standard `handle` for worker-style routing and a `handleMiddleware` wrapper to allow Hono middleware to interact with `EventContext` bindings directly.
Sources: [src/adapter/cloudflare-pages/handler.ts:32-46](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts#L32-L46), [src/adapter/cloudflare-pages/handler.ts:49-102](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts#L49-L102)
## JSX Rendering Pipeline
The JSX subsystem (`src/jsx/`) is a comprehensive template rendering engine supporting both static string generation and DOM-based client-side rendering. It includes intrinsic element support, context management, and hooks (`src/jsx/hooks/index.ts`).
Hooks such as `useState` manage component-local state by maintaining a persistent hook index tracked during the rendering cycle within the context stack. This ensures that state is scoped to the specific component instance during the node tree build process.
Sources: [src/jsx/hooks/index.ts:182-243](https://github.com/blade47/hono/blob/main/src/jsx/hooks/index.ts#L182-L243)
## Routing Engine
Routing in Hono is handled by a dispatchable router interface. The `src/router.ts` defines the contract for routers. The system supports multiple router strategies (RegExp, Trie, Linear, Pattern) to allow for performance tuning depending on the complexity of the route configuration.
The dispatcher returns an array of handler-parameter mappings, which are interpreted by the core `Hono` engine to resolve execution flow based on the method and path provided by the incoming `Request`.
Sources: [src/router.ts:25-52](https://github.com/blade47/hono/blob/main/src/router.ts#L25-L52)
## Middleware and Factory Patterns
Hono uses a factory-based approach to middleware initialization. The `src/helper/factory/` module provides a way to define middleware and handlers with strict type-safety, which is crucial given the complex intersection types generated by Hono's route builder.
```mermaid
flowchart TD
App[Hono Application] --> Factory[Factory Helper]
Factory --> MW[Middleware Logic]
Factory --> Hndlr[Handlers]
MW --> Context[Context Propagation]
```
Sources: [src/helper/factory/index.ts:332-366](https://github.com/blade47/hono/blob/main/src/helper/factory/index.ts#L332-L366)
## Static Site Generation (SSG) Mechanism
The SSG helper in `src/helper/ssg/` provides a programmatic interface to crawl the Hono app and generate static files. The process involves a `pool` of concurrent requests that hit the app's `fetch` method, collecting the response content and determining the output path based on the MIME type.
The resolution of the output file extension is governed by `determineExtension`:
1. Check against the user-provided mapping (provided via `options.extensionMap`).
2. Fallback to `getExtension` (via `src/utils/mime`).
3. Default to `.html` if no MIME match is found.
Sources: [src/helper/ssg/ssg.ts:99-108](https://github.com/blade47/hono/blob/main/src/helper/ssg/ssg.ts#L99-L108)
## Design Trade-offs
The current codebase reflects several deliberate architectural choices:
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Middleware-on-Request | High flexibility and request-lifecycle control | Complex type-level definitions |
| Adapter-based Core | Ubiquitous runtime compatibility | Increased maintenance surface for platform-specific edge cases |
| Factory Helpers | Strong type inference in handlers | Verbose boilerplate in setup |
Sources: [src/helper/factory/index.ts:332-366](https://github.com/blade47/hono/blob/main/src/helper/factory/index.ts#L332-L366), [src/adapter/cloudflare-pages/handler.ts:32-46](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts#L32-L46)
## Related
- [[Overview]]
- [[Quick Start]]
---
## Application Routing
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/application-routing
Relevant source files
The following files were used as context for generating this wiki page:
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts)
- [src/helper/route/index.ts](https://github.com/blade47/hono/blob/main/src/helper/route/index.ts)
- [src/request.ts](https://github.com/blade47/hono/blob/main/src/request.ts)
- [src/router/reg-exp-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts)
Application Routing is the foundational subsystem in Hono responsible for mapping incoming HTTP requests to their corresponding handler functions. It acts as the central traffic controller, enabling developers to build complex API surfaces by registering middleware and route handlers to specific URL paths and HTTP methods.
The system is designed with a pluggable router architecture, allowing the application instance to remain agnostic of the specific matching strategy. By decoupling the registration API from the execution engine, Hono achieves both high performance and modularity, supporting different router implementations that prioritize either raw speed or advanced pattern matching.
During the lifecycle of a request, the routing subsystem translates an incoming URL into a result provided by the router implementation. This result contains the ordered list of handlers (middleware and route handlers) that should execute for the given request. This dispatch mechanism ensures that global middleware, path-specific middleware, and final route handlers are executed in the correct sequence, respecting the order of registration.
## Pluggable Router Architecture
Hono employs a strategy-based routing approach. The main `Hono` class inherits from a base class that operates on a generic `Router` interface, while specific implementations are provided at instantiation.
The `SmartRouter` acts as a high-level router that can aggregate multiple specialized routers. For example, the standard `Hono` implementation uses a `SmartRouter` that orchestrates both `RegExpRouter` and `TrieRouter` to balance performance across different path complexity levels.
```mermaid
classDiagram
class Router {
<>
add(method, path, handler)
match(method, path)
}
class HonoBase {
router: Router
#addRoute()
#dispatch()
}
class SmartRouter {
routers: Router[]
}
Router <|.. SmartRouter
HonoBase o-- Router
```
Sources: [src/hono-base.ts:10-11, 118](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L10-L11#L118), [src/hono.ts:3-5, 30](https://github.com/blade47/hono/blob/main/src/hono.ts#L3-L5#L30)
## Route Registration Flow
When a user calls `app.get()`, `app.post()`, or similar methods, the routing subsystem performs a multi-step registration process via private methods within the base class.
1. **Normalization**: The path is merged with any current `_basePath`.
2. **Data Structure Creation**: A `RouterRoute` object is instantiated, capturing the method, path, and handler reference.
3. **Router Insertion**: The handler and metadata are passed to the `router.add()` method for indexing.
4. **Internal Tracking**: The route is stored in an internal array (`this.routes`) for later retrieval.
```mermaid
flowchart TD
A["app.get(path, handler)"] --> B["HonoBase.#addRoute()"]
B --> C["mergePath(this._basePath, path)"]
C --> D["Create RouterRoute object"]
D --> E["router.add()"]
D --> F["this.routes.push(r)"]
```
Sources: [src/hono-base.ts:124, 134, 385-396](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L124#L134#L385-L396)
## Request Dispatching Mechanism
When a request arrives at the `fetch()` method, the subsystem executes the dispatch logic. This is the critical "hot path" where the router is queried.
1. **Host-Aware Path Extraction**: The `getPath` function (which can be customized) isolates the pathname.
2. **Matching**: The router's `match(method, path)` method returns an ordered array of handlers.
3. **Context Construction**: A `Context` object is initialized with the route matches.
4. **Handler Composition**: The `compose` function wraps all handlers (both middleware and the final route handler) into a single, chained execution pipeline.
> [!IMPORTANT]
> The composition step is skipped if only one handler is matched, an optimization that avoids the overhead of creating an execution chain for trivial routes.
Sources: [src/hono-base.ts:419-427, 430](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L419-L427#L430)
## Route Resolution and Tie-breaking
When multiple patterns could potentially match a single incoming request (e.g., wildcards vs. exact paths), the `RegExpRouter` handles the selection process:
* **Static Path Preference**: Static routes (those without wildcards or parameters) are checked against a `staticMap` first for O(1) lookup.
* **Trie Ordering**: For parameterized routes, paths are indexed into a Trie.
* **Registration Order**: In the `RegExpRouter`, routes are sorted by path length and static status; if paths have equal specificity, the order of registration determines the match priority (the first registered route wins).
Sources: [src/router/reg-exp-router/router.ts:47-49, 62](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L47-L49#L62)
## Route Helpers and Introspection
The routing subsystem exposes tools to inspect the active route during the execution of a handler. These helpers are defined in `src/helper/route/index.ts`.
| Helper | Purpose | Source |
| :--- | :--- | :--- |
| `matchedRoutes(c)` | Returns all routes that matched the current request. | [src/helper/route/index.ts:32-34](https://github.com/blade47/hono/blob/main/src/helper/route/index.ts#L32-L34) |
| `routePath(c)` | Returns the registered path for the current handler. | [src/helper/route/index.ts:58-59](https://github.com/blade47/hono/blob/main/src/helper/route/index.ts#L58-L59) |
| `baseRoutePath(c)` | Returns the base path of the route segment. | [src/helper/route/index.ts:82-83](https://github.com/blade47/hono/blob/main/src/helper/route/index.ts#L82-L83) |
## Usage Example
The following example demonstrates how to define an application, apply middleware, and use a sub-router for route grouping.
```typescript
import { Hono } from 'hono'
const app = new Hono()
const subApp = new Hono()
// Middleware applied to all routes
app.use('*', async (c, next) => {
console.log('Request received')
await next()
})
// Sub-app grouping
subApp.get('/posts', (c) => c.text('List of posts'))
app.route('/api', subApp) // Path becomes /api/posts
// Direct route definition
app.get('/hello/:name', (c) => {
const name = c.req.param('name')
return c.text(`Hello ${name}`)
})
// Dispatching for testing
const response = await app.request('/api/posts')
```
Sources: [src/hono-base.ts:157, 191, 208](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L157#L191#L208)
## Related
- [[Request Lifecycle]]
- [[Smart Router]]
---
## Request Lifecycle
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/request-lifecycle
Relevant source files
The following files were used as context for generating this wiki page:
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/client/client.ts](https://github.com/blade47/hono/blob/main/src/client/client.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/request.ts](https://github.com/blade47/hono/blob/main/src/request.ts)
The Request Lifecycle in Hono defines the journey of an HTTP request from its arrival in an adapter (such as AWS Lambda or a standard worker environment) to its final dispatch through the Hono router and the subsequent generation of an HTTP response. This architecture is designed to decouple the application logic from specific platform-dependent event structures, ensuring portability across cloud environments while maintaining strict performance and type-safety.
At the core of this lifecycle is the `Hono` instance, which acts as a centralized controller. When a request arrives, it is either wrapped by an adapter-specific processor or directly consumed by `app.fetch()`. The lifecycle transitions through route matching, middleware composition, handler execution, and finally, response finalization. By normalizing platform events into standard Web API `Request` objects, Hono provides a consistent interface for developers regardless of the underlying runtime.
The design emphasizes a "middleware-first" dispatching pattern. Because Hono treats handlers and middleware as fundamentally the same type (`H`), it can compose them into a unified execution chain. This choice prevents the "split-logic" problem found in other frameworks where handlers and middleware must be handled through different mechanisms, thus creating a predictable flow of execution that is highly resistant to race conditions during response generation.
## Request Normalization (Adapters)
In platform-specific environments like AWS Lambda, the request lifecycle begins with an event processor. Since different triggers (API Gateway v1/v2, ALB, Lattice) deliver event payloads in different shapes, Hono utilizes an `EventProcessor` abstract class to normalize these inputs into a standard `Request` object.
The `getProcessor` function acts as the entry point, inspecting the event object to determine the appropriate implementation. It uses platform-specific guards like `isProxyEventALB` or `isProxyEventV2` to identify the event type. Once determined, the chosen processor extracts paths, headers, and bodies—transforming them into a standard `Request` instance that the core application can understand.
Sources: [src/adapter/aws-lambda/handler.ts:639-651](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L639-L651), [src/adapter/aws-lambda/handler.ts:278-402](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L278-L402)
## Dispatch and Routing
Once a `Request` is normalized, the lifecycle moves to `app.fetch()`. This method delegates to `app.#dispatch()`, which is responsible for finding the handler for the given URL path. The router compares the request method and path against registered `RouterRoute` definitions.
The winner is chosen by the router's internal match mechanism, which returns an array of handler candidates. If multiple routes overlap, the selection is determined by the specific `Router` implementation used. The `Hono` core relies on this matching to populate the `Context` object, which encapsulates the entire state of the current request lifecycle, including environmental bindings and path parameters.
Sources: [src/hono-base.ts:406-466](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L406-L466), [src/hono-base.ts:388-397](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L388-L397)
## Middleware Composition
Hono uses a composition pattern to process requests through an ordered chain. The `compose` function processes the array of handlers returned by the router. This flow ensures that each middleware has the opportunity to perform work both before and after the next handler in the chain is executed, using the `next()` function.
> [!WARNING]
> If a developer fails to call `await next()` or return a `Response` object within the lifecycle, the framework will eventually throw an error stating the "Context is not finalized," as the chain cannot safely complete.
The lifecycle control flow follows a recursive `next()` pattern. If a handler throws an exception, the lifecycle jumps to the `errorHandler` associated with the Hono instance, which converts the error into an appropriate HTTP response, ensuring that the system never enters an unhandled state.
Sources: [src/hono-base.ts:450-466](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L450-L466), [src/hono-base.ts:406-410](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L406-L410)
## Context Encapsulation
The `Context` object is the state container for the entire request lifecycle. It is created at the start of the `#dispatch` call. Its primary responsibility is to act as a bridge between the raw `Request` and the user-land handler.
- **Storage:** It maintains a `Map` of variables (`#var`) set via `c.set()`.
- **Response Builder:** It tracks the status, headers, and the final response object.
- **Helper Methods:** Methods like `c.text()`, `c.json()`, and `c.html()` act as convenience factories that populate the `#res` property while simultaneously applying default headers (like `Content-Type`).
Sources: [src/context.ts:293-361](https://github.com/blade47/hono/blob/main/src/context.ts#L293-L361), [src/context.ts:515-780](https://github.com/blade47/hono/blob/main/src/context.ts#L515-L780)
## Response Finalization
The final phase of the lifecycle involves transforming the returned object back into a platform-compatible result. In the case of AWS Lambda, the processor’s `createResult` method handles this. It performs critical transformations:
1. **Serialization:** Converting `ArrayBuffer` or text into the format required by the gateway (sometimes requiring base64 encoding).
2. **Cookie Management:** Extracting `set-cookie` headers into the structure expected by the specific gateway version.
3. **Encoding:** Checking if the content encoding (e.g., gzip) necessitates binary handling.
Sources: [src/adapter/aws-lambda/handler.ts:344-386](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L344-L386)
## Request Lifecycle Execution Flow
The following diagram illustrates the high-level movement of a request through the Hono system.
```mermaid
flowchart TD
A["Incoming Event (e.g., Lambda)"] --> B["EventProcessor.createRequest()"]
B --> C["app.fetch(request)"]
C --> D["Router.match()"]
D --> E["compose(handlers)"]
E --> F["Execute Middleware/Handler"]
F --> G["Context.finalized = true"]
G --> H["Processor.createResult()"]
H --> I["Outgoing Response"]
```
Sources: [src/adapter/aws-lambda/handler.ts:148-157](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L148-L157), [src/hono-base.ts:406-466](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L406-L466)
## Common Utilities and Constants
| Component | Purpose |
| :--- | :--- |
| `HonoRequest` | Wraps standard `Request` with Hono-specific routing and parameter helpers. |
| `Context` | Holds the state of the current request, including bindings and response data. |
| `EventProcessor` | Normalizes platform events (AWS/Cloudflare) into a standardized interface. |
| `compose` | Executes the middleware chain using the `next()` pattern. |
Sources: [src/request.ts:19](https://github.com/blade47/hono/blob/main/src/request.ts#L19), [src/context.ts:293](https://github.com/blade47/hono/blob/main/src/context.ts#L293), [src/adapter/aws-lambda/handler.ts:278](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts#L278)
## Related
- [[Application Routing]]
- [[Context Execution]]
---
## Context Execution
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/context-execution
Relevant source files
The following files were used as context for generating this wiki page:
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/client/client.ts](https://github.com/blade47/hono/blob/main/src/client/client.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/validator/validator.ts](https://github.com/blade47/hono/blob/main/src/validator/validator.ts)
"Context Execution" refers to the Hono lifecycle management system centered on the `Context` class. It serves as the primary interface between the incoming HTTP request and the developer's handler functions. The subsystem acts as a bridge, abstracting platform-specific details (like AWS Lambda events or Cloudflare Workers `FetchEvent`) into a unified API.
The purpose of this subsystem is to provide a consistent, type-safe execution environment regardless of the deployment target. By wrapping raw requests into a `Context` instance, Hono allows middleware and handlers to interact with request data, state variables, and response generation in an identical manner, whether running in a serverless function, a standard Node server, or a browser client.
Key design decisions include a lazy-initialization pattern for heavy components like `HonoRequest` and `Headers`, ensuring that features are only processed if accessed. The `Context` object manages the state of the request/response lifecycle, tracking finalization status and providing methods to return varied content types (JSON, text, HTML).
## The `Context` Interface and Responsibilities
The `Context` class is the central orchestrator for a single execution unit. It maintains the internal state of the request-response flow, holding references to the raw request, environment bindings, and match results from the router.
### Lifecycle State and Finalization
The `Context` maintains an internal `finalized` flag (line 317) to track the state of the response. Once a handler has committed a response, the `finalized` property is set to `true` (line 433). This guard ensures that subsequent modifications, such as calling `.header()` or setting a response, operate on the already finalized object or handle the state accordingly.
> [!IMPORTANT]
> The `finalized` flag is the primary invariant for response safety. When `this.finalized` is true, attempts to modify headers force a deep-copy of the existing response to maintain functional purity while allowing late-stage modifications (lines 516-518).
## Request Processing Flow
The flow of a request starts at the application's `fetch` method and proceeds through the following orchestration chain:
1. **Request Handling**: The `HonoBase` class's `fetch` method initiates the request handling process.
2. **Context Initialization**: The `Context` wraps the raw `Request`. It does not immediately parse the body or headers; it uses a getter for `.req` (lines 366-369) which lazily instantiates `HonoRequest` only upon access.
3. **Middleware Composition**: The matching handlers are combined using `compose()` (from `hono-base.ts`), which wraps the handlers into a middleware pipeline. Each handler receives the `Context` instance.
4. **Handler Execution**: The handlers read from and write to the `Context` (using `.set()`, `.get()`, or response helpers like `.json()`).
5. **Finalization**: The final handler returns a `Response` object, which is then returned through the pipeline and dispatched to the platform-specific adapter.
```mermaid
flowchart TD
A[Incoming Request] --> B[Hono.fetch]
B --> C[Router.match]
C --> D[Context Initialization]
D --> E[compose: Middleware Pipeline]
E --> F[Handler Execution]
F --> G[c.text / c.json / c.html]
G --> H[Finalized Response]
```
Sources: [src/hono-base.ts:406-466](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L406-L466), [src/context.ts:352-361](https://github.com/blade47/hono/blob/main/src/context.ts#L352-L361)
## Adapters and Platform Integration
The `adapter/aws-lambda/handler.ts` file illustrates how the context is extended to support platform-specific triggers. The `handle` function acts as an adapter, translating incoming AWS Lambda events into the standard `Request` object expected by Hono.
- **Processors**: The adapter uses dedicated logic for different event types (`APIGatewayProxyEvent`, `ALBProxyEvent`, `LatticeProxyEventV2`). These extract `path`, `method`, `headers`, and `body` from the event and map them to standard Web `Request` types (lines 318-341).
- **Result Mapping**: After the `Context` generates a response, the adapter's `createResult` (lines 344-386) ensures the response headers and body are translated back into the structure expected by the API Gateway or Load Balancer.
## Response Helpers
The context exposes several helper methods for common HTTP operations. These methods are designed to facilitate communication.
| Method | Return Type | Purpose |
| :--- | :--- | :--- |
| `.json()` | `JSONRespondReturn` | Encodes objects to JSON and sets `Content-Type`. |
| `.text()` | `TypedResponse` | Returns a `text/plain` response. |
| `.html()` | `Response` | Returns a `text/html` response. |
| `.redirect()` | `TypedResponse` | Sets the `Location` header and a 302 status. |
These methods internally call `this.#newResponse`, which merges global state (`this.#status`, `this.#preparedHeaders`) with per-call parameters to generate the final `Response` instance (lines 604-639).
## Error Handling Mechanism
Errors within the context execution are captured by the `compose` pipeline logic defined in `hono-base.ts`. If a handler throws, the `errorHandler` function defined at the `HonoBase` level is invoked to generate a response.
> [!NOTE]
> The `Context` exposes an `.error` property (line 333). This is typically used in middleware to inspect if a handler further down the chain has triggered an exception, allowing for custom error logging without full-stop termination.
```mermaid
sequenceDiagram
participant User
participant Hono
participant Handler
User->>Hono: fetch()
Hono->>Handler: execute()
alt Success
Handler-->>Hono: Response
Hono-->>User: Response
else Failure
Handler-->>Hono: throw Error
Hono->>Hono: errorHandler()
Hono-->>User: Error Response
end
```
Sources: [src/hono-base.ts:35-42](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L35-L42), [src/hono-base.ts:462-464](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L462-L464)
## Design Trade-offs
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| **Lazy Loading** | Minimizes memory/compute for unused context parts | Small overhead for first-time property access |
| **Class-based Context** | Encapsulated state and fluent API | Higher memory footprint per request |
## Practical Example
This snippet demonstrates how a developer uses the context within a standard route handler to set state, inspect environment variables, and return a JSON response.
```typescript
import { Hono } from 'hono'
const app = new Hono<{ Bindings: { API_KEY: string } }>()
app.get('/data', async (c) => {
// Use .env bindings
const apiKey = c.env.API_KEY
// Set context variables
c.set('user', { id: 1 })
// Return JSON
return c.json({ status: 'ok', data: 'hello' }, 200)
})
```
Sources: [src/context.ts:311-312](https://github.com/blade47/hono/blob/main/src/context.ts#L311-L312), [src/context.ts:541](https://github.com/blade47/hono/blob/main/src/context.ts#L541), [src/context.ts:704](https://github.com/blade47/hono/blob/main/src/context.ts#L704)
## Related
- [[Request Lifecycle]]
- [[Middleware Composition]]
---
## Middleware Composition
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/middleware-composition
Relevant source files
The following files were used as context for generating this wiki page:
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/middleware/secure-headers/secure-headers.ts](https://github.com/blade47/hono/blob/main/src/middleware/secure-headers/secure-headers.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/middleware/cache/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/cache/index.ts)
- [src/middleware/compress/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/compress/index.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/cloudflare-pages/handler.ts)
- [src/middleware/combine/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/combine/index.ts)
Middleware composition in Hono is a powerful architectural pattern that allows developers to chain independent request handlers into a unified pipeline. This mechanism enables cross-cutting concerns—such as security, caching, and compression—to be applied uniformly across routes or specific path patterns without polluting individual business-logic handlers.
At its core, composition follows a "decorator-like" pattern, where each middleware has the power to pre-process requests, execute subsequent handlers via a control-flow callback function, and post-process responses. This flow allows Hono to build complex stacks of behavior that are both modular and testable, keeping the application's request-response lifecycle clean.
The subsystem serves as the glue for Hono's extensibility. By leveraging the control-flow callback pattern, composition facilitates fine-grained control over execution flow. Developers can conditionally skip middleware, intercept early responses, or perform teardown logic after other handlers have completed. This design choice is fundamental to Hono's performance, as it avoids unnecessary overhead by resolving the execution order statically during router initialization and dynamically via the `compose` pipeline during runtime dispatch.
## Pipeline Dispatch and Control Flow
Hono employs a composition pipeline to sequence handlers for a matched route. The primary flow involves receiving a `Request`, routing it to identify a set of handlers, and then executing them sequentially. Each handler receives a `Context` object and a control-flow callback function. If a handler calls this function, control is passed to the next handler in the chain.
The mechanism relies on `compose`, which wraps an array of handlers. If a request matches multiple routes, the handlers are collapsed into a single execution stream. Crucially, if a handler does not call the provided callback and provides a response, the pipeline halts, and the final response is returned to the client, effectively short-circuiting the remaining middleware.
Sources: [src/hono-base.ts:406-466](https://github.com/blade47/hono/blob/main/src/hono-base.ts#L406-L466)
## Composable Middleware Strategies
The `combine` module provides higher-order composition primitives: `some`, `every`, and `except`. These functions act as logic gates for middleware execution.
* `some`: Executes a list of handlers until one completes successfully. It short-circuits execution if a handler reports success (typically by returning `true`).
* `every`: Requires all handlers to execute successfully. If any handler fails, the chain terminates.
* `except`: Conditional execution where middleware is applied unless the `condition` (either a path string or a function) is met.
These primitives allow for sophisticated logic such as "skip authentication if the request comes from a local network" or "only run rate-limiting if the user lacks a valid bearer token."
```mermaid
flowchart TD
A[Start] --> B{"some() logic"}
B -->|Check Handler 1| C{Passed?}
C -->|Yes| D[Execute callback]
C -->|No| E[Check Handler 2]
E --> F{Passed?}
F -->|Yes| D
F -->|No| G[Throw Error]
```
Sources: [src/middleware/combine/index.ts:38-164](https://github.com/blade47/hono/blob/main/src/middleware/combine/index.ts#L38-L164)
## Content-Driven Pipeline Transformations
Some middleware, like `compress`, act as stream-processing decorators. In this mechanism, the middleware calls the control-flow callback to allow the application logic to build a response, then captures that response to apply a `CompressionStream`.
This "wrap and transform" pattern is essential for modifying response bodies on the fly. The middleware must perform careful checks: it verifies that the `Content-Type` is compressible, checks for `no-transform` instructions in the `Cache-Control` header, and ensures that the response is not already compressed.
> [!IMPORTANT]
> The `compress` middleware converts strong ETags to weak ETags because the compression process alters the exact byte representation of the response body. This is a critical invariant to maintain cache consistency.
Sources: [src/middleware/compress/index.ts:86-121](https://github.com/blade47/hono/blob/main/src/middleware/compress/index.ts#L86-L121)
## Context-Aware Injection
Middleware composition frequently uses the `Context` to share state across the pipeline. For example, the `secure-headers` middleware provides a `NONCE` generator. This function checks the context for an existing nonce; if not found, it generates a new one and stores it via `ctx.set()`. This state is then accessible to downstream view engines or template renderers.
The `secureHeaders` middleware also evaluates callbacks before calling the control-flow callback, ensuring that any dependencies required by the response (like a nonce) are populated before the main handler runs, yet the final header injection happens after the main handler produces the response.
Sources: [src/middleware/secure-headers/secure-headers.ts:137-228](https://github.com/blade47/hono/blob/main/src/middleware/secure-headers/secure-headers.ts#L137-L228)
## Lifecycle Management: Cache Middleware
The `cache` middleware demonstrates a hybrid approach where it acts both as a guard and a pipeline modifier. It attempts a match against the Cache API before calling the control-flow callback. If a match exists, it terminates the request lifecycle early by returning the cached response.
If no match exists, it proceeds with the control-flow callback, waits for the application logic to populate the response, and then uses `c.executionCtx.waitUntil()` to asynchronously cache the response in the background. This ensures the request completion is not blocked by cache insertion.
```mermaid
sequenceDiagram
participant Req as Request
participant Mid as Cache Middleware
participant App as Application Handler
participant C as Cache API
Req->>Mid: Process
Mid->>C: match(key)
alt Cached Response Found
Mid-->>Req: Return Cached Response
else No Hit
Mid->>App: await callback()
App-->>Mid: Return New Response
Mid->>C: put(key, res)
Mid-->>Req: Return Response
end
```
Sources: [src/middleware/cache/index.ts:138-180](https://github.com/blade47/hono/blob/main/src/middleware/cache/index.ts#L138-L180)
## Performance and Selection Logics
When multiple middlewares or handlers are present, Hono manages execution priority. The router stores routes, and during dispatch, the matched route handlers are collected. The `compose` function ensures they are executed in the order of registration.
One critical safety guard exists in composition: `isNextCalled` in the `some()` implementation of the `combine` middleware. This variable prevents multiple invocations of the downstream pipeline, guaranteeing that if a condition is satisfied, the request lifecycle invariants are maintained.
> [!TIP]
> Use `combine` primitives for declarative, clean composition rather than manually tracking state across multiple `app.use()` registrations.
Sources: [src/middleware/combine/index.ts:39-68](https://github.com/blade47/hono/blob/main/src/middleware/combine/index.ts#L39-L68)
## Worked Example: Declarative Security Pipeline
This example demonstrates combining multiple security middlewares to protect an API endpoint.
```typescript
import { Hono } from 'hono'
import { secureHeaders, NONCE } from 'hono/secure-headers'
import { some } from 'hono/combine'
import { bearerAuth } from 'hono/bearer-auth'
const app = new Hono()
// Apply security headers with a custom CSP nonce
app.use(secureHeaders({
contentSecurityPolicy: {
scriptSrc: [NONCE],
}
}))
// Use combined logic: skip authentication for specific paths
app.use('/api/*', some(
(c) => c.req.path.startsWith('/api/public'),
bearerAuth({ token: 'secret-token' })
))
app.get('/api/data', (c) => c.json({ data: 'secure' }))
```
Sources: [src/middleware/secure-headers/secure-headers.ts:184-190](https://github.com/blade47/hono/blob/main/src/middleware/secure-headers/secure-headers.ts#L184-L190), [src/middleware/combine/index.ts:38-68](https://github.com/blade47/hono/blob/main/src/middleware/combine/index.ts#L38-L68)
## Related
- [[Context Execution]]
---
## RegExp Router
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/regexp-router
Relevant source files
The following files were used as context for generating this wiki page:
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [package.json](https://github.com/blade47/hono/blob/main/src/package.json)
- [src/client/client.ts](https://github.com/blade47/hono/blob/main/src/client/client.ts)
- [src/router/reg-exp-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/router/reg-exp-router/prepared-router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/prepared-router.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/utils/url.ts](https://github.com/blade47/hono/blob/main/src/utils/url.ts)
- [src/router/linear-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/linear-router/router.ts)
- [src/helper/ssg/ssg.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/ssg.ts)
The `RegExpRouter` is a high-performance routing engine designed for speed by converting standard URL routing patterns into a single, optimized regular expression. Unlike naive routers that perform linear scans or depth-first tree traversals for every incoming request, `RegExpRouter` compiles the entire routing table into a regex-based matcher. This design minimizes the per-request overhead, making it particularly effective in environments where routing performance is a critical path.
The architecture relies on a `Trie` data structure to preprocess route definitions. During the registration phase, the router tracks path structures and converts variables (like `:id`) and wildcards (`*`) into corresponding capturing groups. This structure is then serialized into a regular expression. When a request arrives, the router uses this single regex to identify the matching handler index in a single pass, significantly reducing the algorithmic complexity of route resolution.
`RegExpRouter` is one of the foundational routers used within Hono. It is typically employed by the `SmartRouter`, which combines different routing strategies to provide the best balance of flexibility and performance. By implementing the `Router` interface, it remains drop-in compatible with other routing implementations, allowing developers to switch underlying engines without altering their business logic.
## The Trie Preprocessing Mechanism
Before a regex can be generated, the router must organize the input paths into a `Trie` structure. This ensures that hierarchical path segments are handled correctly and that potential routing ambiguities are resolved. The `Trie` insertion logic acts as the primary registry for path segments.
When `add(method, path, handler)` is called:
1. The path is tokenized into segments.
2. The `Trie` structure is updated by calling `trie.insert(path, j, pathErrorCheckOnly)`.
3. If a segment contains a parameter (e.g., `:id`), it is handled by the trie nodes to facilitate correct index generation for the final regex output.
Sources: [src/router/reg-exp-router/router.ts:L132-L204](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L132-L187), [src/router/reg-exp-router/trie.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/trie.ts)
## Regex Compilation Logic
Once all routes are registered, the `RegExpRouter` invokes `buildMatcherFromPreprocessedRoutes`. This function performs the transformation from a structured `Trie` to an executable `RegExp` instance.
The compilation process:
1. Traverses the built trie via `trie.buildRegExp()` to generate a path-matching regex.
2. Captures parameter groups so they can be extracted during the `match` operation.
3. Finalizes the regex, which acts as the "Compiled Routing Table" used to dispatch incoming requests.
```mermaid
flowchart TD
A[Start: Build Matcher] --> B[Traverse Trie]
B --> C[trie.buildRegExp]
C --> D[Generate Regex Instance]
D --> E[Finalize Handler Mapping]
E --> F[Return Matcher]
```
Sources: [src/router/reg-exp-router/router.ts:L34-L103](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L34-L103)
## Static Path Handling
The `RegExpRouter` separates path matching into logic for static paths and patterns. During the build process, routes are flagged via a boolean as `!/\*|\/:/.test(route[0])`. Routes without parameters are stored as static entries. During the `match` operation, these are evaluated to ensure optimal performance for standard, non-parameterized routes.
> [!TIP]
> Placing frequently accessed static routes, such as `/health`, before dynamic routes can improve performance in high-throughput applications, as the router optimizes for these constant paths during the trie construction.
Sources: [src/router/reg-exp-router/router.ts:L43-L56](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L43-L56)
## Handler Selection and Tie-Breaking
When multiple handlers might match a single path (e.g., via middleware or overlapping patterns), the router must determine the order of evaluation. The `RegExpRouter` uses a sorting mechanism during the build process:
```typescript
.sort(([isStaticA, pathA], [isStaticB, pathB]) =>
isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
)
```
This logic ensures that routes are ordered such that static routes are favored and dynamic paths are ordered by their path length, establishing a consistent priority for pattern matching.
Sources: [src/router/reg-exp-router/router.ts:L47-L49](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L47-L49)
## The Prepared Router
For static-heavy applications, `RegExpRouter` offers a `PreparedRegExpRouter`. This variant allows the matcher to be pre-built and serialized into a string. This is useful for environments (like cold-start serverless functions) where compiling the router at runtime would be too slow.
- `buildInitParams`: Collects path data and generates the matcher.
- `serializeInitParams`: Converts the internal matcher data into a JSON string that can be safely embedded in a source file.
```mermaid
sequenceDiagram
participant User
participant PRR as PreparedRegExpRouter
participant Matcher
User->>PRR: add(method, path, handler)
PRR->>Matcher: Access pre-compiled regex
Matcher-->>PRR: Return index/params
PRR->>PRR: Update handler array
```
Sources: [src/router/reg-exp-router/prepared-router.ts:L9-L93](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/prepared-router.ts#L9-L93)
## Error Handling and Invariants
The router enforces strict path invariants during construction. If a path is malformed (e.g., illegal segments), it throws an `UnsupportedPathError`.
> [!WARNING]
> The `RegExpRouter` expects well-formed paths. If you add a path that the `Trie` cannot represent due to internal limitations, `PATH_ERROR` will be thrown, causing the router to abort the build process.
Sources: [src/router/reg-exp-router/router.ts:L63-L65](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L63-L65)
## Summary of Design Trade-offs
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Regex Matching | Constant time complexity for routing | Longer initial build time |
| Trie-based pre-processing | Consistent handling of params/wildcards | Higher memory footprint during build |
| Serialization (Prepared) | Near-zero cold start time | Complex setup and build-time tooling |
Sources: [src/router/reg-exp-router/router.ts:L34-L103](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L34-L103), [src/router/reg-exp-router/prepared-router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/prepared-router.ts)
## Related
- [[Smart Router]]
- [[Alternative Routers]]
---
## Smart Router
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/smart-router
Relevant source files
The following files were used as context for generating this wiki page:
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/validator/validator.ts](https://github.com/blade47/hono/blob/main/src/validator/validator.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/middleware/ip-restriction/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/ip-restriction/index.ts)
- [src/router/smart-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/smart-router/router.ts)
- [src/router/reg-exp-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts)
- [src/utils/url.ts](https://github.com/blade47/hono/blob/main/src/utils/url.ts)
- [src/router/reg-exp-router/prepared-router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/prepared-router.ts)
The `SmartRouter` is a high-level orchestration component in the Hono framework designed to bridge the gap between multiple underlying routing strategies. Rather than forcing a singular routing algorithm (like a Trie or Regular Expression) onto all developers, it acts as a dynamic, "smart" proxy that enables Hono to optimize its routing performance based on the actual usage patterns of an application.
The core problem addressed by `SmartRouter` is the selection of the most efficient routing mechanism. Different routers perform optimally under different conditions (e.g., Trie-based routers often excel at static lookups, while RegExp-based routers offer flexibility for complex patterns). `SmartRouter` achieves this by maintaining an internal list of candidate routers and deferring the definitive choice until the first request is matched.
Upon the first request, the component iterates through its configured router implementations, attempting to register all previously queued routes sequentially into each candidate. The first router to successfully process the full routing table for the given request context is selected as the "active" router. Subsequent requests bypass the initialization logic entirely, essentially hot-swapping the `SmartRouter` instance with the performance-proven candidate.
## Design Philosophy and Router Selection
`SmartRouter` functions as a wrapper that implements the standard `Router` interface, yet hides a sophisticated "activation" phase. Its design follows a "fail-safe and promote" pattern: it maintains a list of candidate routers provided via configuration and, on the first call to `match`, attempts to populate them until one succeeds.
The mechanism uses a deferred routing strategy:
1. All `add` calls (for registering routes) are buffered in a local `private #routes` array.
2. The `match` method, when called for the first time, performs a "build" operation.
3. It iterates through the provided `routers` list, calling `add` for every buffered route on each candidate.
4. If a router successfully matches the request, that router is marked active.
> [!IMPORTANT]
> The `SmartRouter` guarantees that the router chosen is capable of handling the entire existing route set, not just the single request that triggered the selection. This ensures that the state consistency of the routing table is preserved across the transition from buffer to execution.
Sources: [src/router/smart-router/router.ts:4-32](https://github.com/blade47/hono/blob/main/src/router/smart-router/router.ts#L4-L32)
## Initialization and Lifecycle
`SmartRouter` is typically instantiated within the Hono constructor. By default, it is configured with a prioritized list (e.g., `RegExpRouter` followed by `TrieRouter`). This allows the system to attempt the most performant or generic router first.
```mermaid
classDiagram
class Router {
<>
+add(method, path, handler)
+match(method, path)
}
class SmartRouter {
-routers: Router[]
-routes: [method, path, handler][]
+add()
+match()
}
Router <|-- SmartRouter
```
Sources: [src/hono.ts:28-32](https://github.com/blade47/hono/blob/main/src/hono.ts#L28-L32)
## Call-Chain Execution: The First Match
The most complex logic within `SmartRouter` is the first-match orchestration. The control flow is explicitly designed to handle potential failures in individual router builders (like `UnsupportedPathError`).
1. **`add()`**: Buffers the route into `this.#routes`.
2. **`match()` (First invocation)**:
- Checks if `this.#routes` is non-null (indicating build phase).
- Loops through `this.#routers`.
- Calls `router.add(...)` for every entry in the buffered `routes` array.
- Executes `router.match(method, path)`.
- If an `UnsupportedPathError` occurs, the loop continues to the next router.
- Upon success, it rebinds `this.match` to the active router's `match` function, effectively becoming a pass-through for subsequent requests.
Sources: [src/router/smart-router/router.ts:13-50](https://github.com/blade47/hono/blob/main/src/router/smart-router/router.ts#L13-L50)
## The Re-binding Mechanism
Once an active router is identified, `SmartRouter` modifies itself to minimize overhead for future requests. By re-binding the `match` function, it bypasses its own logic loop entirely.
```typescript
// The line that shifts responsibility from SmartRouter to the chosen implementation
this.match = router.match.bind(router);
```
This specific assignment prevents unnecessary conditional checks during the high-frequency path of route lookup, effectively turning the `SmartRouter` into a thin wrapper around the chosen router.
Sources: [src/router/smart-router/router.ts:46](https://github.com/blade47/hono/blob/main/src/router/smart-router/router.ts#L46)
## Guard Conditions and Invariants
`SmartRouter` relies on several critical invariants to maintain the integrity of the routing table:
> [!CAUTION]
> Once `match` is called, the state of the router is frozen. The check `if (!this.#routes) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT)` inside the `add` method prevents any further modifications to the route set after the selection of an active router has occurred.
Sources: [src/router/smart-router/router.ts:14-16](https://github.com/blade47/hono/blob/main/src/router/smart-router/router.ts#L14-L16)
## Usage Example
The following code illustrates how `SmartRouter` is initialized within the standard Hono framework instantiation.
```typescript
import { Hono } from 'hono';
import { SmartRouter } from 'hono/router/smart-router';
import { RegExpRouter } from 'hono/router/reg-exp-router';
import { TrieRouter } from 'hono/router/trie-router';
// Manual instantiation (normally handled by the Hono class)
const myRouter = new SmartRouter({
routers: [new RegExpRouter(), new TrieRouter()]
});
const app = new Hono({ router: myRouter });
app.get('/api/users', (c) => c.json({ status: 'ok' }));
```
Sources: [src/hono.ts:26-32](https://github.com/blade47/hono/blob/main/src/hono.ts#L26-L32)
## Related
- [[RegExp Router]]
- [[Alternative Routers]]
---
## Alternative Routers
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/alternative-routers
Relevant source files
The following files were used as context for generating this wiki page:
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [src/types.ts](https://github.com/blade47/hono/blob/main/src/types.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/main/src/preset/quick.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/main/src/hono.ts)
- [src/utils/url.ts](https://github.com/blade47/hono/blob/main/src/utils/url.ts)
- [src/router/reg-exp-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts)
- [src/router/linear-router/router.ts](https://github.com/blade47/hono/blob/main/src/router/linear-router/router.ts)
Alternative Routers in Hono provide specialized mechanisms for path matching, allowing the framework to balance performance and complexity based on specific use cases. By decoupling the routing engine from the core application framework, Hono enables developers to swap matching logic for different environments or traffic patterns.
The router subsystem acts as a critical intermediary. When a request hits the Hono instance, it is transformed into a standard request object and passed to the router's `match` function. The router then efficiently resolves the incoming path and method against the registered routes, returning a handler set that the runtime subsequently executes.
The system supports multiple router implementations—such as `RegExpRouter`, `TrieRouter`, and `LinearRouter`. By using a `SmartRouter` (or other selection logic), Hono can choose the most performant matcher at runtime, or developers can customize the router initialization. This architecture ensures that the overhead of request dispatching remains minimal regardless of the number of routes or the complexity of path parameters.
## Smart Router Orchestration
The `SmartRouter` acts as a facade, coordinating between multiple underlying routing strategies. In `src/preset/quick.ts`, the `Hono` class initializes with a `SmartRouter` configured to use both `LinearRouter` and `TrieRouter`. This composition allows the system to leverage the strengths of different matching algorithms concurrently.
```mermaid
classDiagram
class Hono {
+router: SmartRouter
}
class SmartRouter {
-routers: Router[]
+match(method, path)
}
class TrieRouter {
+match(method, path)
}
class LinearRouter {
+match(method, path)
}
Hono *-- SmartRouter
SmartRouter o-- TrieRouter
SmartRouter o-- LinearRouter
```
Sources: [src/preset/quick.ts:13-24](https://github.com/blade47/hono/blob/main/src/preset/quick.ts#L13-L24), [src/hono.ts:16-34](https://github.com/blade47/hono/blob/main/src/hono.ts#L16-L34)
## RegExpRouter Implementation
The `RegExpRouter` is designed for high-performance route resolution by compiling paths into regular expressions. The `buildMatcherFromPreprocessedRoutes` function is central to this mechanism: it sorts routes, inserting them into a `Trie` structure to produce a highly efficient regex that performs the matching task in a single pass.
> [!NOTE]
> The `RegExpRouter` pre-compiles routes into a regex matcher. The registration order and path complexity directly impact the compiled complexity.
The `buildAllMatchers` method acts as the lifecycle trigger for finalization. It cycles through the routes, builds the `MatcherMap`, and then explicitly nullifies internal structures (`#middleware = #routes = undefined`) to free memory and prevent further modifications.
Sources: [src/router/reg-exp-router/router.ts:34-103](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L34-L103), [src/router/reg-exp-router/router.ts:208-222](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L208-L222)
## LinearRouter Matching Logic
The `LinearRouter` uses a flat array of route registrations, iterating through them linearly (`#routes: [string, string, T][]`). This approach is optimal for small route sets where the overhead of building a complex trie or regex would outweigh the cost of direct comparison.
The core matching algorithm resides in the `match` method, which uses a label-based approach for static routes and regex-based matching for parameters. It contains a `ROUTES_LOOP` label that acts as a control-flow break mechanism, enabling the loop to move to the next candidate immediately if the current path segment fails to match.
Sources: [src/router/linear-router/router.ts:11-23](https://github.com/blade47/hono/blob/main/src/router/linear-router/router.ts#L11-L23), [src/router/linear-router/router.ts:25-110](https://github.com/blade47/hono/blob/main/src/router/linear-router/router.ts#L25-L110)
## Path Parameter Extraction
Both routers interact closely with `src/utils/url.ts` to process segments and extract parameters. The `extractGroupsFromPath` function performs a destructive replacement on the path to isolate segments enclosed in `{}`. This transformation allows the internal routing logic to treat parameter placeholders as discrete tokens during the trie insertion or regex generation phase.
| Function | Responsibility |
| :--- | :--- |
| `splitPath` | Tokenizes paths by `/` and removes empty segments. |
| `getPattern` | Returns a `Pattern` tuple for route segments (wildcards or regexes). |
| `checkOptionalParameter` | Resolves routes with optional segments (e.g., `:id?`) into flattened variants. |
Sources: [src/utils/url.ts:23-33](https://github.com/blade47/hono/blob/main/src/utils/url.ts#L23-L33), [src/utils/url.ts:171-206](https://github.com/blade47/hono/blob/main/src/utils/url.ts#L171-L206)
## Error Handling and Invariants
The router system employs strict checks during route registration. When the trie encounters a conflict—specifically, when a path pattern cannot be resolved predictably—it throws an `UnsupportedPathError`.
> [!CAUTION]
> The router assumes that the configuration passed via the constructor (e.g., `options.router`) is immutable after initialization. If the internal state is modified post-match, the results become non-deterministic.
Sources: [src/router/reg-exp-router/router.ts:61-65](https://github.com/blade47/hono/blob/main/src/router/reg-exp-router/router.ts#L61-L65)
## Design Trade-offs
The current architecture prioritizes flexibility. The system supports swapping routers at build time, and providing multiple implementations allows Hono to optimize based on the application's unique route topology.
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| `RegExpRouter` compilation | Fast execution for large route sets. | High initial startup cost. |
| `LinearRouter` array | Memory efficient and fast for small sets. | O(N) lookup time. |
| `SmartRouter` facade | Easy runtime switching between matchers. | Slightly increased abstraction layer overhead. |
Sources: [src/hono.ts:28-32](https://github.com/blade47/hono/blob/main/src/hono.ts#L28-L32), [src/preset/quick.ts:20-22](https://github.com/blade47/hono/blob/main/src/preset/quick.ts#L20-L22)
## Related
- [[RegExp Router]]
- [[Smart Router]]
---
## JSX Renderer
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/jsx-renderer
Relevant source files
The following files were used as context for generating this wiki page:
- [src/jsx/dom/render.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/jsx/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/components.ts)
- [src/jsx/streaming.ts](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts)
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [src/jsx/dom/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/intrinsic-element/components.ts)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/jsx/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-element/components.ts)
- [src/jsx/context.ts](https://github.com/blade47/hono/blob/main/src/jsx/context.ts)
- [src/jsx/dom/client.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/client.ts)
- [src/utils/html.ts](https://github.com/blade47/hono/blob/main/src/utils/html.ts)
- [src/jsx/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-dev-runtime.ts)
- [src/jsx/dom/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-dev-runtime.ts)
- [src/jsx/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/index.ts)
- [src/jsx/dom/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-runtime.ts)
- [src/helper/html/index.ts](https://github.com/blade47/hono/blob/main/src/helper/html/index.ts)
- [src/jsx/dom/server.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/server.ts)
- [src/jsx/dom/css.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/css.ts)
- [src/jsx/dom/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/index.ts)
- [runtime-tests/deno-jsx/deno.react-jsx.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno-jsx/deno.react-jsx.json)
- [runtime-tests/deno-jsx/deno.precompile.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno-jsx/deno.precompile.json)
- [src/jsx/dom/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/components.ts)
- [runtime-tests/deno/deno.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno/deno.json)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/jsx/types.ts](https://github.com/blade47/hono/blob/main/src/jsx/types.ts)
- [src/jsx/intrinsic-elements.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-elements.ts)
The JSX Renderer is the core component within the Hono framework responsible for converting JSX structures into actionable DOM elements (client-side) or serialized HTML (server-side). Unlike standard virtual DOM libraries that might prioritize universal hydration, the Hono JSX renderer is specifically architected to be lightweight, fast, and highly compatible with Hono's middleware-based request pipeline, facilitating both traditional server-side rendering (SSR) and modern dynamic DOM updates.
At its core, the system distinguishes between a static "base" JSX representation (used for initial serialization) and a "DOM" renderer that enables reactive, stateful updates. The renderer uses a custom reconciliation process that minimizes DOM manipulation by intelligently tracking component hierarchies, context, and hook state. By leveraging specialized internal tags and efficient property application, it ensures that changes to application state translate directly into optimized instructions for the underlying web browser.
The JSX Renderer is deeply integrated into Hono's `context.ts` and middleware systems. It provides the mechanism by which handlers can respond with complex HTML structures while maintaining the ability to inject dynamic metadata or perform streaming rendering, effectively bridging the gap between static HTML generation and interactive client-side application state.
## The Reconciliation Algorithm: Build and Apply
The rendering mechanism is split into two primary phases: `build` (determining what should change) and `apply` (executing those changes against the real DOM).
```mermaid
flowchart TD
A["Trigger Update"] --> B["build(context, node)"]
B --> C{"Invoke Tags
and Reconcile Children"}
C --> D["Calculate
vR (nodes to remove)"]
D --> E["apply(node, container)"]
E --> F["Update
Actual DOM"]
```
Sources: [src/jsx/dom/render.ts:497-665](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L497-L665), [src/jsx/dom/render.ts:387-481](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L387-L481)
The `build` phase recursively traverses the component tree. When a component function is invoked, the renderer checks if its output matches the previous state. If an old version of the node exists, it performs a key-based lookup to find a match and attempts to patch properties rather than recreate elements. If no match is found, the node is marked for creation.
> [!CAUTION]
> If a node lacks a `key`, the renderer reconciles children based strictly on their `tag`. This requires caution: switching components of the same tag type but different underlying implementation can lead to stale state being preserved in the stash.
Sources: [src/jsx/dom/render.ts:541-555](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L541-L555)
The `apply` phase then consumes the children lists populated by the `build` phase. It maps these internal virtual nodes to browser-native `HTMLElement` instances. For efficiency, it performs property application by comparing `attributes` against `oldAttributes`, updating event listeners (using a `getEventSpec` lookup table) and styles dynamically.
## Lifecycle and Effect Management
The renderer supports lifecycle hooks (`useEffect`, `useLayoutEffect`, `useInsertionEffect`) by batching these callbacks in the `apply` phase. Once the DOM is updated, the renderer processes the collected effects, ensuring that `useInsertionEffect` runs first, followed by `useLayoutEffect`, and finally scheduling `useEffect` inside a `requestAnimationFrame`.
| Hook Type | Timing |
| :--- | :--- |
| `useInsertionEffect` | Before DOM mutations/layouts |
| `useLayoutEffect` | After DOM updates but before paint |
| `useEffect` | After paint (scheduled via `requestAnimationFrame`) |
Sources: [src/jsx/dom/render.ts:462-480](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L462-L480)
## Middleware Integration: `jsxRenderer`
The `jsxRenderer` middleware integrates the JSX rendering system into the broader Hono request lifecycle. It allows developers to register a layout component that wraps every `c.render()` call.
```typescript
// Example of how the jsxRenderer middleware is used to register a layout
app.get(
'/page/*',
jsxRenderer(({ children, Layout }) => {
return (
{children}
)
})
)
```
Sources: [src/middleware/jsx-renderer/index.ts:116-129](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts#L116-L129)
This middleware uses the `createRenderer` function, which binds the `Context` and `Layout` to the `render` function provided to the user. When `c.render()` is called, it constructs the component tree with a `RequestContext.Provider`, ensuring that downstream components can access the `Hono` context object directly via `useRequestContext()`.
Sources: [src/middleware/jsx-renderer/index.ts:33-80](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts#L33-L80)
## Performance Considerations
The renderer employs several strategies to maintain performance:
1. **Try-Catch Attribute Validation**: Instead of regex-validating every attribute name before application, the renderer applies them and only traps errors (e.g., `InvalidCharacterError`) at the point of application. This makes common-path rendering significantly faster.
2. **Event Caching**: The `eventCache` object pre-defines frequently used events like `onClick` to avoid repeated regex matching for standard DOM handlers.
3. **Memoization Support**: The `memo` utility uses a `DOM_MEMO` property on components. The reconciler checks this function before proceeding with a sub-tree update, allowing components to skip rendering entirely if properties remain stable.
Sources: [src/jsx/dom/render.ts:158-163](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L158-L163), [src/jsx/dom/render.ts:115-118](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L115-L118), [src/jsx/base.ts:384-405](https://github.com/blade47/hono/blob/main/src/jsx/base.ts#L384-L405)
## Related
- [[DOM Rendering]]
- [[Streaming Utilities]]
---
## DOM Rendering
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/dom-rendering
Relevant source files
The following files were used as context for generating this wiki page:
- [src/jsx/dom/render.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/jsx/hooks/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/hooks/index.ts)
- [src/jsx/streaming.ts](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts)
- [src/jsx/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/components.ts)
- [src/jsx/dom/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/intrinsic-element/components.ts)
- [src/jsx/dom/client.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/client.ts)
- [src/jsx/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-element/components.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/jsx/context.ts](https://github.com/blade47/hono/blob/main/src/jsx/context.ts)
- [src/jsx/dom/server.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/server.ts)
- [src/jsx/dom/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/index.ts)
- [src/jsx/dom/css.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/css.ts)
- [src/jsx/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/index.ts)
- [src/jsx/dom/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-runtime.ts)
- [src/jsx/dom/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-dev-runtime.ts)
- [src/utils/html.ts](https://github.com/blade47/hono/blob/main/src/utils/html.ts)
- [src/jsx/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-dev-runtime.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/helper/css/index.ts](https://github.com/blade47/hono/blob/main/src/helper/css/index.ts)
- [src/jsx/dom/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/components.ts)
- [src/jsx/types.ts](https://github.com/blade47/hono/blob/main/src/jsx/types.ts)
- [src/jsx/intrinsic-elements.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-elements.ts)
DOM Rendering is a lightweight, runtime-focused engine within the Hono framework designed to bridge the gap between declarative JSX templates and imperative browser DOM manipulations. Unlike server-side rendering (SSR) implementations that serialize JSX into HTML strings, this subsystem maintains an internal virtual-tree representation of nodes, enabling efficient updates, hook management, and dynamic interaction within the client-side environment. It is the core mechanism that allows Hono applications to remain responsive without the overhead of heavy virtual DOM reconciliation found in traditional libraries.
The architecture centers around the `Node` structure—a unified interface that distinguishes between static text nodes and interactive element nodes. By tracking previous props (`pP`) and virtual children (`vC`), the renderer minimizes browser reflows through surgical DOM updates. It supports React-like hooks such as `useState`, `useEffect`, and `useMemo`, which are integrated directly into the lifecycle of each node object, allowing state-driven UI updates to occur precisely where needed without traversing the entire component tree.
Interaction with the system is typically handled through the `render()` or `hydrateRoot()` APIs, which initiate the transformation of a JSX structure into a live DOM tree. Once rendered, the renderer automatically manages effect cleanup, event binding, and context propagation, ensuring that declarative updates result in predictable DOM transitions. This design prioritizes runtime performance, using native browser capabilities and minimal overhead to handle the complexities of component-based UI development.
## The Node Object Model
The core of the DOM renderer is the `NodeObject` type, a recursive data structure representing an element in the DOM tree. Unlike a simple HTML string, the `NodeObject` caches runtime metadata required for reconciliation and reactive updates.
| Field | Purpose |
| :--- | :--- |
| `props` | Current component properties. |
| `pP` | Previous properties, used to detect changes for incremental updates. |
| `vC` | Virtual children: an array of nested `Node` instances. |
| `e` | The live `SupportedElement` or `Text` node associated with this entry. |
| `c` | The parent `Container` (HTMLElement or DocumentFragment). |
| `s` | A flag indicating whether to skip build/apply steps (performance optimization). |
| `[DOM_STASH]` | An internal storage array for hooks (index, effects, context). |
Sources: [src/jsx/dom/render.ts:41-65](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L41-L65)
## Control Flow: Reconciliation and Building
The renderer process uses a two-phase cycle: `build` (determining the structure) and `apply` (syncing that structure to the live DOM). The `build` function recursively transforms JSX nodes into the `Node` internal representation.
When a node requires an update, the renderer uses a `WeakMap` (`updateMap`) to consolidate pending changes, ensuring that rapid state updates trigger only the necessary re-rendering. During the `build` phase, the system maintains a `buildDataStack` to track the context and the current node being processed, which is essential for `useContext` and hook initialization.
```mermaid
flowchart TD
A["Render Call"] --> B["Build Phase"]
B --> C["Recursive VDOM Construction"]
C --> D["Identify Changes (Diffing)"]
D --> E["Apply Phase"]
E --> F["DOM Mutation (Append/Insert/Update)"]
F --> G["Execute Effects (useEffect/useLayoutEffect)"]
```
Sources: [src/jsx/dom/render.ts:497-665](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L497-L665), [src/jsx/dom/render.ts:740-781](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L740-L781)
## Hook Execution and Lifecycle
Hooks are indexed within the `[DOM_STASH]` field of a `NodeObject`. The system utilizes a `current hook index` to ensure that consecutive calls to hooks within a component remain synchronized across re-renders.
> [!NOTE]
> `useEffect` callbacks are scheduled via `requestAnimationFrame` to decouple DOM mutations from effect execution, while `useLayoutEffect` runs synchronously after the DOM is updated but before the browser paints.
The system ensures correct cleanup via the `removeNode` function, which explicitly triggers registered effect cleanups and clears references stored in the `refCleanupMap`.
Sources: [src/jsx/dom/render.ts:341-362](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L341-L362), [src/jsx/hooks/index.ts:260-287](https://github.com/blade47/hono/blob/main/src/jsx/hooks/index.ts#L260-L287)
## Attribute and Event Handling
The renderer optimizes property application by distinguishing between event listeners, special attributes (like `dangerouslySetInnerHTML`), and standard DOM attributes.
- **Event Delegation:** Attributes starting with "on" (e.g., `onClick`) are parsed into `[eventName, capture]` pairs. The system maintains an `eventCache` for frequently used events to speed up lookups.
- **Form Values:** Special handling is provided for `SELECT` and `INPUT` fields, where `applySelectValue` or direct property assignment is used instead of standard `setAttribute` to reflect internal states like `selectedIndex` or `checked`.
- **Attribute Application:** Standard attributes are set using `container.setAttribute`. The renderer uses a `try-catch` block around `setAttribute` specifically to catch `InvalidCharacterError`, avoiding a slow upfront regex validation of every attribute name.
Sources: [src/jsx/dom/render.ts:115-132](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L115-L132), [src/jsx/dom/render.ts:164-272](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L164-L272)
## Error Boundaries and Streaming
The DOM renderer integrates with `ErrorBoundary` components by maintaining an error stack in the `Context`. When a component throws an error, the renderer looks for the closest `DOM_ERROR_HANDLER` in the hierarchy.
If an error boundary is found, the system wraps the fallback in an update queue. This allows the boundary to recover gracefully. The renderer uses a `cancelBuild` symbol to halt the reconciliation process for subtrees that have crashed, preventing them from contaminating the global DOM state until a recovery render is triggered.
Sources: [src/jsx/dom/render.ts:612-657](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L612-L657)
## Worked Example: Client-Side Rendering
To render an application, use the `createRoot` API. This pattern creates a consistent root-level controller that can manage subsequent updates via `useState`.
```typescript
import { createRoot } from 'hono/jsx/dom/client';
const App = ({ name }: { name: string }) => Hello {name}
;
const root = createRoot(document.getElementById('root')!);
root.render();
// Later, trigger an update if the component was setup to be reactive
```
Sources: [src/jsx/dom/client.ts:23-66](https://github.com/blade47/hono/blob/main/src/jsx/dom/client.ts#L23-L66)
## Related
- [[JSX Renderer]]
---
## Streaming Utilities
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/streaming-utilities
Relevant source files
The following files were used as context for generating this wiki page:
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/jsx/dom/render.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/aws-lambda/handler.ts)
- [src/jsx/streaming.ts](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts)
- [src/helper/streaming/stream.ts](https://github.com/blade47/hono/blob/main/src/helper/streaming/stream.ts)
- [src/helper/streaming/sse.ts](https://github.com/blade47/hono/blob/main/src/helper/streaming/sse.ts)
- [src/jsx/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/components.ts)
- [src/middleware/compress/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/compress/index.ts)
- [src/utils/stream.ts](https://github.com/blade47/hono/blob/main/src/utils/stream.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/helper/proxy/index.ts](https://github.com/blade47/hono/blob/main/src/helper/proxy/index.ts)
- [src/request.ts](https://github.com/blade47/hono/blob/main/src/request.ts)
- [src/adapter/lambda-edge/handler.ts](https://github.com/blade47/hono/blob/main/src/adapter/lambda-edge/handler.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/middleware/etag/digest.ts](https://github.com/blade47/hono/blob/main/src/middleware/etag/digest.ts)
- [src/middleware/body-limit/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/body-limit/index.ts)
- [src/helper/streaming/index.ts](https://github.com/blade47/hono/blob/main/src/helper/streaming/index.ts)
- [src/utils/html.ts](https://github.com/blade47/hono/blob/main/src/utils/html.ts)
- [src/jsx/dom/server.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/server.ts)
- [src/client/fetch-result-please.ts](https://github.com/blade47/hono/blob/main/src/client/fetch-result-please.ts)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/helper/streaming/text.ts](https://github.com/blade47/hono/blob/main/src/helper/streaming/text.ts)
- [src/helper/ssg/ssg.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/ssg.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/main/src/hono-base.ts)
- [src/jsx/dom/client.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/client.ts)
Streaming Utilities in Hono provide the infrastructure necessary for handling long-lived HTTP responses, server-sent events (SSE), and incremental rendering of HTML. By leveraging standard `ReadableStream` and `WritableStream` primitives, these utilities enable efficient, non-blocking data delivery, which is critical for real-time applications and optimized web performance.
At the architecture level, Hono abstracts the low-level complexities of stream management and browser-to-server connection handling. The primary objective is to allow developers to transmit data to the client as it becomes available, rather than waiting for an entire document or payload to be generated. This is achieved through a consistent interface that sits atop standard web APIs, ensuring compatibility across different JavaScript runtimes like Cloudflare Workers, Node.js, and Bun.
These utilities are deeply integrated into the Hono request/response lifecycle. Components like `StreamingApi` and `SSEStreamingApi` manage the communication pipes, while high-level helpers like `stream`, `streamText`, and `streamSSE` simplify the orchestration of these pipes. By centralizing the logic for chunked encoding, cleanup of abort events, and error propagation, these utilities ensure that streaming remains predictable and memory-efficient.
## Core Streaming API Surface
The `StreamingApi` class provides the foundational interface for writing chunks to an underlying `WritableStream`. It handles the conversion of strings to byte buffers, supports `writeln` for convenience, and maintains internal flags to track the stream's state, preventing redundant or erroneous operations once a stream has been aborted or closed.
```mermaid
classDiagram
class StreamingApi {
-writer: WritableStreamDefaultWriter
+responseReadable: ReadableStream
+aborted: boolean
+closed: boolean
+write(input)
+writeln(input)
+close()
+abort()
}
class SSEStreamingApi {
+writeSSE(message)
}
StreamingApi <|-- SSEStreamingApi
```
Sources: [src/utils/stream.ts:6-98](https://github.com/blade47/hono/blob/main/src/utils/stream.ts#L6-L98), [src/helper/streaming/sse.ts:13-45](https://github.com/blade47/hono/blob/main/src/helper/streaming/sse.ts#L13-L45)
## Server-Sent Events (SSE) Mechanism
The SSE implementation extends the base streaming API to enforce the specific format required by the SSE protocol (`data:`, `event:`, `id:`, etc.). The `writeSSE` method performs validation to ensure that headers like `event` or `id` do not contain illegal newline characters, which would terminate the message prematurely.
> [!WARNING]
> SSE message fields must not contain `\r` or `\n`. The `writeSSE` method throws an `Error` if these characters are detected in `event`, `id`, or `retry` fields to ensure protocol integrity.
Sources: [src/helper/streaming/sse.ts:18-44](https://github.com/blade47/hono/blob/main/src/helper/streaming/sse.ts#L18-L44)
## Stream Lifecycle and Bun Compatibility
Streaming in Hono includes specific handling for platform inconsistencies, particularly regarding the `ReadableStream` lifecycle. In older versions of Bun, the `ReadableStream` used for response objects was not always automatically cancelled upon request abort. The `stream` and `streamSSE` helpers add event listeners to the request signal to manually invoke `stream.abort()` when an abort event occurs.
```mermaid
flowchart TD
A["Request received"] --> B{"Is old Bun version?"}
B -- Yes --> C["Add signal abort listener"]
B -- No --> D["Create TransformStream"]
C --> D
D --> E["Create StreamingApi"]
E --> F["Start async cb(stream)"]
F --> G["return c.newResponse(stream.responseReadable)"]
```
Sources: [src/helper/streaming/stream.ts:15-22](https://github.com/blade47/hono/blob/main/src/helper/streaming/stream.ts#L15-L22), [src/helper/streaming/sse.ts:80-87](https://github.com/blade47/hono/blob/main/src/helper/streaming/sse.ts#L80-L87)
## Incremental JSX Rendering
The `renderToReadableStream` function allows for incremental generation of HTML content from JSX trees. It tracks dependencies (callbacks) and resolves them as they become available. This mechanism is the backbone of Hono's streaming support for JSX, enabling components to suspend rendering until data is fetched.
> [!NOTE]
> `renderToReadableStream` monitors `cancelled` status on each tick. If a stream is cancelled, it stops pushing data, which prevents memory leaks or unnecessary processing in the middle of long-running rendering tasks.
Sources: [src/jsx/streaming.ts:142-216](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts#L142-L216)
## Error Handling and Cleanup
Error handling is implemented through standard try-catch-finally patterns in the main runner functions (`run` for SSE and anonymous wrappers for general streams). When an error occurs in the callback, the `onError` hook is triggered.
| Hook Type | Responsibility |
| :--- | :--- |
| `onError` | Receives the `Error` and `StreamingApi` instance to perform custom error logic or logging. |
| `Finally` block | Guarantees that `stream.close()` is called regardless of execution success, ensuring resource cleanup. |
Sources: [src/helper/streaming/stream.ts:26-42](https://github.com/blade47/hono/blob/main/src/helper/streaming/stream.ts#L26-L42), [src/helper/streaming/sse.ts:47-68](https://github.com/blade47/hono/blob/main/src/helper/streaming/sse.ts#L47-L68)
## Usage Example: Basic Text Streaming
The following example shows how to use the `streamText` utility to push data to the client incrementally.
```typescript
import { Hono } from 'hono'
import { streamText } from 'hono/streaming'
const app = new Hono()
app.get('/stream', (c) => {
return streamText(c, async (stream) => {
await stream.writeln('Starting stream...')
await stream.sleep(1000)
await stream.write('Streaming complete.')
})
})
```
Sources: [src/helper/streaming/text.ts:6-15](https://github.com/blade47/hono/blob/main/src/helper/streaming/text.ts#L6-L15)
## Related
- [[JSX Renderer]]
---
## CSS Styling
URL: https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/css-styling
Relevant source files
The following files were used as context for generating this wiki page:
- [src/middleware/secure-headers/secure-headers.ts](https://github.com/blade47/hono/blob/main/src/middleware/secure-headers/secure-headers.ts)
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [src/helper/css/common.ts](https://github.com/blade47/hono/blob/main/src/helper/css/common.ts)
- [src/jsx/dom/render.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts)
- [src/helper/css/index.ts](https://github.com/blade47/hono/blob/main/src/helper/css/index.ts)
- [src/jsx/streaming.ts](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts)
- [src/jsx/utils.ts](https://github.com/blade47/hono/blob/main/src/jsx/utils.ts)
- [src/jsx/dom/css.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/css.ts)
- [src/middleware/compress/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/compress/index.ts)
- [src/jsx/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/components.ts)
- [src/jsx/dom/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/intrinsic-element/components.ts)
- [src/helper/ssg/ssg.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/ssg.ts)
- [src/jsx/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-element/components.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/utils/html.ts](https://github.com/blade47/hono/blob/main/src/utils/html.ts)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/helper/html/index.ts](https://github.com/blade47/hono/blob/main/src/helper/html/index.ts)
- [src/helper/ssg/utils.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/utils.ts)
- [src/helper/dev/index.ts](https://github.com/blade47/hono/blob/main/src/helper/dev/index.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/jsx/intrinsic-element/common.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-element/common.ts)
- [src/helper/ssg/index.ts](https://github.com/blade47/hono/blob/main/src/helper/ssg/index.ts)
- [src/adapter/deno/index.ts](https://github.com/blade47/hono/blob/main/src/adapter/deno/index.ts)
- [src/jsx/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/index.ts)
- [src/utils/compress.ts](https://github.com/blade47/hono/blob/main/src/utils/compress.ts)
- [src/jsx/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-dev-runtime.ts)
Hono provides a robust, experimental CSS-in-JS solution designed to work seamlessly in both server-side rendering (SSR) and client-side DOM environments. This subsystem addresses the challenge of managing scoped styles in a modular application by generating hash-based class names at runtime, minimizing style collisions, and supporting efficient style injection.
At its core, the CSS styling mechanism treats CSS rules as structured data. By utilizing template literals, it allows developers to define styles naturally, while the underlying helper functions transform these templates into minified style strings and associated class name objects. These objects encapsulate selectors, class identifiers, and the actual style string, which are then used by the rendering engine to either inject standard `