Skip to main content
doc0blade47/honodocumentation home
Sign in

Context Storage

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The Hono context storage mechanism leverages Node.js Execution Context AsyncLocalStorage to maintain request-scoped access to the Execution Context instance across asynchronous call boundaries without explicitly passing parameters through every function. By integrating with middleware execution flow, it binds incoming requests to an asynchronous store so that nested handlers, utility functions, and background services can retrieve active request details on demand. This architecture eliminates the need for manual context threading in deeply nested business logic while ensuring proper isolation between concurrent requests in supported runtimes.

Sources: src/middleware/context-storage/index.ts:6-11, src/middleware/context-storage/index.ts:43-47

AsyncLocalStorage Architecture

Storage Mechanism

The underlying storage relies on Node.js AsyncLocalStorage initialized as a module-level constant instance typed against the Hono Execution Context. This storage container maintains request isolation by capturing asynchronous execution contexts across disparate call frames.

import { AsyncLocalStorage } from 'node:async_hooks'
import type { Context } from '../../context'
import type { Env, MiddlewareHandler } from '../../types'
 
const asyncLocalStorage = new AsyncLocalStorage<Context>()

Sources: src/middleware/context-storage/index.ts:6-10

Note

asyncLocalStorage is a single module-scoped singleton instance shared across all requests handled by the middleware, relying on Node's async execution tracking to segregate concurrent stores.

Sources: src/middleware/context-storage/index.ts:6-10

Lifecycle Integration

The middleware wraps downstream execution by passing the current Context instance into the asyncLocalStorage.run method alongside the next dispatch function. This anchors the active Execution Context to the asynchronous boundary for the duration of all subsequent middleware and route handlers.

export const contextStorage = (): MiddlewareHandler => {
  return async function contextStorage(c, next) {
    await asyncLocalStorage.run(c, next)
  }
}

Sources: src/middleware/context-storage/index.ts:43-47

Warning

Any asynchronous operations executed outside the scope established by asyncLocalStorage.run will lose access to the bound Context, resulting in undefined stores when calling retrieval functions.

Sources: src/middleware/context-storage/index.ts:43-47

Context Storage Middleware

Middleware Initialization

The contextStorage factory function returns a MiddlewareHandler closure designed to intercept incoming request dispatches. When invoked, it yields an asynchronous middleware function that establishes the request boundary before invoking downstream handlers.

export const contextStorage = (): MiddlewareHandler => {
  return async function contextStorage(c, next) {
    await asyncLocalStorage.run(c, next)
  }
}

Sources: src/middleware/context-storage/index.ts:43-47

Context Binding During Dispatch

During the request dispatch cycle, the middleware binds the active Context instance (c) to the module-scoped AsyncLocalStorage instance by executing asyncLocalStorage.run(c, next). This wraps the remaining middleware chain and route handlers (next) within a tracked asynchronous execution frame.

return async function contextStorage(c, next) {
  await asyncLocalStorage.run(c, next)
}

Sources: src/middleware/context-storage/index.ts:44-46

Note

The next function passed into asyncLocalStorage.run ensures that all subsequent asynchronous yields, promises, and downstream handlers inherit the bound Context transparently.

Sources: src/middleware/context-storage/index.ts:44-46

Accessing Context Outside Handlers

Retrieval Functions

The public API exports two functions for accessing the active request Execution Context outside of standard route handlers: tryGetContext and getContext. Both functions accept an optional generic type parameter E extending Env to type-check environment bindings and variables. tryGetContext queries the underlying AsyncLocalStorage store directly, returning the active Context<E> instance or undefined if invoked outside an active request scope.

export const tryGetContext = <E extends Env = Env>(): Context<E> | undefined => {
  return asyncLocalStorage.getStore() as Context<E> | undefined
}

Sources: src/middleware/context-storage/index.ts:49-51

Tip

Use tryGetContext in utility functions or shared modules that may execute both within and outside of HTTP request lifecycles, allowing graceful handling of missing context states without throwing exceptions.

Sources: src/middleware/context-storage/index.ts:49-51

Error Handling and Enforcement

The getContext function wraps tryGetContext with a validation check, throwing an explicit error when no request context is present in the asynchronous store. This provides strict guarantees for service functions or helpers that depend unconditionally on active request bindings.

export const getContext = <E extends Env = Env>(): Context<E> => {
  const context = tryGetContext<E>()
  if (!context) {
    throw new Error('Context is not available')
  }
  return context
}

Sources: src/middleware/context-storage/index.ts:53-59

Warning

Calling getContext outside of a request scope initialized by the middleware throws a Context is not available error, halting execution.

Sources: src/middleware/context-storage/index.ts:55-57

Runtime Compatibility and Constraints

Node.js and Async Context Foundation

The underlying storage mechanism relies on AsyncLocalStorage imported directly from the Node.js built-in node:async_hooks module. This restricts native context propagation support to runtimes that fully implement Node.js asynchronous hook APIs or provide compatible runtime shims.

import { AsyncLocalStorage } from 'node:async_hooks'
import type { Context } from '../../context'
import type { Env, MiddlewareHandler } from '../../types'
 
const asyncLocalStorage = new AsyncLocalStorage<Context>()

Sources: src/middleware/context-storage/index.ts:6-10

Note

Modern JavaScript runtimes such as Node.js, Bun, and Deno natively support AsyncLocalStorage, ensuring seamless execution of the context storage middleware across these environments.

Sources: src/middleware/context-storage/index.ts:6-10

Isolation Guarantees and Error Boundaries

Because asyncLocalStorage is instantiated as a module-scoped constant, concurrent requests handled by the server maintain strict state isolation. Each asynchronous execution frame created by asyncLocalStorage.run encapsulates its own Context reference, preventing cross-request data leakage even during concurrent asynchronous yields.

const asyncLocalStorage = new AsyncLocalStorage<Context>()

Sources: src/middleware/context-storage/index.ts:10-10

Caution

Spawning independent asynchronous tasks or background promises using native setTimeout or unawaited promise chains outside of the tracked middleware boundary will detach execution from the active store, causing tryGetContext to return undefined and getContext to throw an unhandled error.

Sources: src/middleware/context-storage/index.ts:43-58

Was this page helpful?