Orientation Arc
Routing Algorithms
Rendering and JSX
Runtime Adapters
Middleware Ecosystem
Developer Helpers
System Utilities
The following files were used as context for generating this wiki page:
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.
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, src/adapter/aws-lambda/handler.ts:278-402
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, src/hono-base.ts:388-397
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, src/hono-base.ts:406-410
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.
Map of variables (#var) set via c.set().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, src/context.ts:515-780
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:
ArrayBuffer or text into the format required by the gateway (sometimes requiring base64 encoding).set-cookie headers into the structure expected by the specific gateway version.Sources: src/adapter/aws-lambda/handler.ts:344-386
The following diagram illustrates the high-level movement of a request through the Hono system.
Sources: src/adapter/aws-lambda/handler.ts:148-157, src/hono-base.ts:406-466
Sources: src/request.ts:19, src/context.ts:293, src/adapter/aws-lambda/handler.ts:278