Skip to main content
doc0blade47/honodocumentation home
Sign in

Router Contracts

Last updated Oct 12, 2026100% grounded
Relevant source files

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

Overview

Hono defines a generic Router Contracts through the Router<T> interface, standardizing how route registration and execution path resolution behave across multiple routing backends Linear and Pattern Routers, RegExp Router, and Trie and Smart Routers. By establishing uniform method signatures for adding paths and matching request methods against registered endpoints, the system allows backends like LinearRouter, PatternRouter, RegExpRouter, and TrieRouter to be swapped interchangeably inside applications (Application Core). These contracts establish strict behaviors around immutable matchers and path constraints, such as throwing UnsupportedPathError when conflicting route syntaxes occur during compilation or evaluation.

Sources: src/router.ts:25-52, src/router.ts:101-103, src/router/linear-router/router.ts:11-143, src/router/pattern-router/router.ts:8-42, src/router/reg-exp-router/router.ts:122-204, src/router/trie-router/router.ts:5-27, src/router/smart-router/router.ts:4-61, src/hono-base.ts:65-65

Unified Router Interface Architecture

Router Interface Contract

The generic Router<T> interface establishes the core contract that every routing backend implements. It defines three primary members: a name string property identifying the router implementation, an add method for registering paths, and a match method for executing lookups.

 * Interface representing a router.
 *
 * @template T - The type of the handler.
 */
export interface Router<T> {
  /**
   * The name of the router.
   */
  name: string
 
  /**
   * Adds a route to the router.
   *
   * @param method - The HTTP method (e.g., 'get', 'post').
   * @param path - The path for the route.
   * @param handler - The handler for the route.
   */
  add(method: string, path: string, handler: T): void
 
  /**
   * Matches a route based on the given method and path.
   *
   * @param method - The HTTP method (e.g., 'get', 'post').
   * @param path - The path to match.
   * @returns The result of the match.
   */
  match(method: string, path: string): Result<T>
}

Sources: src/router.ts:25-52

To support this interface uniformly, the module exports constants defining HTTP methods and error messages utilized during route registration and compilation checks.

 * Constant representing all HTTP methods in uppercase.
 */
export const METHOD_NAME_ALL = 'ALL' as const
/**
 * Constant representing all HTTP methods in lowercase.
 */
export const METHOD_NAME_ALL_LOWERCASE = 'all' as const
/**
 * Array of supported HTTP methods.
 */
export const METHODS = ['get', 'post', 'put', 'delete', 'options', 'patch'] as const
/**
 * Error message indicating that a route cannot be added because the matcher is already built.
 */
export const MESSAGE_MATCHER_IS_ALREADY_BUILT =
  'Can not add a route since the matcher is already built.'
 

Sources: src/router.ts:7-23

Note

The METHOD_NAME_ALL and METHOD_NAME_ALL_LOWERCASE constants represent wildcard HTTP methods ('ALL' and 'all') used to register handlers matching any incoming request method.

Interface Implementation Registry

Different routing strategies fulfill the Router<T> contract across the codebase, exporting their constructors or helper utilities from respective entrypoints.

Router ModuleExported SymbolsDescription
src/router/reg-exp-router/index.tsRegExpRouter, PreparedRegExpRouter, buildInitParams, serializeInitParamsCompiles route trees into single regular expressions
src/router/pattern-router/index.tsPatternRouterEvaluates basic pattern matching for lightweight requirements
src/router/trie-router/index.tsTrieRouterTraverses path segments using node trees
/**
 * @module
 * RegExpRouter for Hono.
 */
 
export { RegExpRouter } from './router'
export { PreparedRegExpRouter, buildInitParams, serializeInitParams } from './prepared-router'

Sources: src/router/reg-exp-router/index.ts:1-7

/**
 * @module
 * PatternRouter for Hono.
 */
 

Sources: src/router/pattern-router/index.ts:1-5

/**
 * @module
 * TrieRouter for Hono.
 */
 
export { TrieRouter } from './router'

Sources: src/router/trie-router/index.ts:1-6

Match Result Representations and Parameter Extraction

Result Data Tuples and Parameter Formats

Route resolution yields a Result<T> tuple that accommodates two distinct structural layouts depending on the underlying router implementation. Each format pairs matched handlers with parameter mappings or value stashes.

 * Type representing a map of parameter indices.
 */
export type ParamIndexMap = Record<string, number>
/**
 * Type representing a stash of parameters.
 */
export type ParamStash = string[]
/**
 * Type representing a map of parameters.
 */
export type Params = Record<string, string>
/**
 * Type representing the result of a route match.
 *
 * The result can be in one of two formats:
 * 1. An array of handlers with their corresponding parameter index maps, followed by a parameter stash.
 * 2. An array of handlers with their corresponding parameter maps.
 *
 * Example:
 *
 * [[handler, paramIndexMap][], paramArray]
 * ```typescript
 * [
 *   [
 *     [middlewareA, {}],                     // '*'
 *     [funcA,       {'id': 0}],              // '/user/:id/*'
 *     [funcB,       {'id': 0, 'action': 1}], // '/user/:id/:action'
 *   ],
 *   ['123', 'abc']
 * ]
 * ```
 *
 * [[handler, params][]]
 * ```typescript
 * [
 *   [
 *     [middlewareA, {}],                             // '*'
 *     [funcA,       {'id': '123'}],                  // '/user/:id/*'
 *     [funcB,       {'id': '123', 'action': 'abc'}], // '/user/:id/:action'
 *   ]
 * ]
 * ```
 */
export type Result<T> = [[T, ParamIndexMap][], ParamStash] | [[T, Params][]]
 

Sources: src/router.ts:55-99

Note

The first format nests a tuple of [T, ParamIndexMap][] alongside a separate ParamStash array (string[]), allowing parameter values to be indexed numerically. The second format directly associates handlers with fully resolved Params dictionaries (Record<string, string>).

Parameter Data Structures

Parameter management relies on specific type definitions for maps and value arrays. The module defines three distinct type aliases to support parameter extraction during route resolution.

Type NameDefinitionDescription
ParamIndexMapRecord<string, number>Maps parameter name keys to numeric index positions within the parameter stash array.
ParamStashstring[]Ordered array of extracted string parameter values referenced by index maps.
ParamsRecord<string, string>Key-value dictionary mapping parameter names directly to their resolved string values.
 * Type representing a map of parameter indices.
 */
export type ParamIndexMap = Record<string, number>
/**
 * Type representing a stash of parameters.
 */
export type ParamStash = string[]
/**
 * Type representing a map of parameters.
 */
export type Params = Record<string, string>

Sources: src/router.ts:55-65

Shared Routing Errors and Matcher Constraints

Matcher State Invariants and Error Messages

During router lifecycle management, route addition is restricted once matching structures have been compiled or initialized. The module defines a specific constant error message to indicate this constraint violation when attempting modifications after compilation.

 * Error message indicating that a route cannot be added because the matcher is already built.
 */
export const MESSAGE_MATCHER_IS_ALREADY_BUILT =
  'Can not add a route since the matcher is already built.'
 

Sources: src/router.ts:19-23

Warning

Attempting to invoke add after a router implementation has built its matcher triggers the error message defined by MESSAGE_MATCHER_IS_ALREADY_BUILT, freezing route registration to ensure thread-safe and deterministic lookups.

Unsupported Path Error Semantics

When path structures fail validation or fall outside supported syntax patterns during registration or matching, routers throw specialized error types extending standard JavaScript exceptions.

/**
 * Error class representing an unsupported path error.
 */
export class UnsupportedPathError extends Error {}

Sources: src/router.ts:100-103

Error Class / ConstantUnderlying Value / BasePurpose
UnsupportedPathErrorErrorSignals that a given route path contains unsupported tokens or structural formatting incompatible with the router backend.
MESSAGE_MATCHER_IS_ALREADY_BUILT'Can not add a route since the matcher is already built.'Prevents post-initialization mutation of router route tables.
export const MESSAGE_MATCHER_IS_ALREADY_BUILT =
  'Can not add a route since the matcher is already built.'
…
*/

Sources: src/router.ts:21-22, src/router.ts:102-102

Route Introspection and Base Path Resolution

Introspection Helpers and Active Route Selection

The routing helper module provides functions to inspect active request contexts and extract matching route metadata. The matchedRoutes function accesses the low-level match result stored on the request object using the GET_MATCH_RESULT constant symbol, mapping the internal tuple structure to an array of RouterRoute definitions.

export const matchedRoutes = (c: Context): RouterRoute[] =>
  // @ts-expect-error c.req[GET_MATCH_RESULT] is not typed
  (c.req as unknown)[GET_MATCH_RESULT][0].map(([[, route]]) => route)

Sources: src/helper/route/index.ts:32-34

export const routePath = (c: Context, index?: number): string =>
  matchedRoutes(c).at(index ?? c.req.routeIndex)?.path ?? ''

Sources: src/helper/route/index.ts:58-59

Note

Both routePath and baseRoutePath accept an optional index argument. This parameter behaves similarly to Array.prototype.at(), allowing negative integers to count backward from the end of the matching root collection while defaulting to c.req.routeIndex.

export const baseRoutePath = (c: Context, index?: number): string =>
  matchedRoutes(c).at(index ?? c.req.routeIndex)?.basePath ?? ''

Sources: src/helper/route/index.ts:82-83

Base Path Resolution and Caching

The basePath function computes the concrete base path with embedded parameters resolved against the active request URL. It utilizes a private WeakMap cache named basePathCacheMap to store calculated base paths per Context instance and index, avoiding redundant substring matching operations during nested application dispatches.

const basePathCacheMap: WeakMap<Context, Record<number, string>> = new WeakMap()
export const basePath = (c: Context, index?: number): string => {
  index ??= c.req.routeIndex
 
  const cache = basePathCacheMap.get(c) || []
  if (typeof cache[index] === 'string') {
    return cache[index]
  }

Sources: src/helper/route/index.ts:106-113

When the unparsed base route path contains dynamic parameters or wildcards matching [:*], basePath splits the path via splitRoutingPath and iterates over each segment. It queries pattern matchers using getPattern to extract substring lengths directly from c.req.path, assembling the final prefix dynamically.

Sources: src/helper/route/index.ts:107-141

Warning

Bypassing index bounds or passing uninitialized request contexts to route introspection helpers will cause lookup failures against GET_MATCH_RESULT. Always invoke these utilities within active request handler flows or middleware layers where routing context has been fully established.

Execution Walkthroughs

Trace Sequence

The resolution of active route paths proceeds through a structured sequence of helper calls.

  1. basePath checks the basePathCacheMap cache using the context and index; on a cache miss, it invokes baseRoutePath.
  2. baseRoutePath calls matchedRoutes to retrieve the active route list.
  3. matchedRoutes reads (c.req as unknown)[GET_MATCH_RESULT][0] and maps the internal tuples to return RouterRoute[].

Sources: src/helper/route/index.ts:32-34, src/helper/route/index.ts:82-83, src/helper/route/index.ts:107-116

Path Tokenization for Route Group Matching

Path Splitting and Group Extraction

The URL utility module manages route path normalization by tokenizing paths, extracting embedded parameter groups, and restoring them during route matching. The splitRoutingPath function coordinates this normalization process by first invoking extractGroupsFromPath on the raw route string.

export const splitRoutingPath = (routePath: string): string[] => {
  const { groups, path } = extractGroupsFromPath(routePath)
 
  const paths = splitPath(path)
  return replaceGroupMarks(paths, groups)
}

Sources: src/utils/url.ts:16-21

The extractGroupsFromPath function scans the input path for bracketed expressions matching /\{[^}]+\}/g. For every discovered group, it generates a placeholder mark using the pattern @${index} and stores the pair in an array before returning the modified path string.

const extractGroupsFromPath = (path: string): { groups: [string, string][]; path: string } => {
  const groups: [string, string][] = []
 
  path = path.replace(/\{[^}]+\}/g, (match, index) => {
    const mark = `@${index}`
    groups.push([mark, match])
    return mark
  })
 
  return { groups, path }
}

Sources: src/utils/url.ts:23-33

Note

Parameter group extraction prevents forward-slash characters contained inside custom regex definitions (such as {id:[0-9/]+}) from breaking segment-based path splitting operations.

export const splitPath = (path: string): string[] => {
  const paths = path.split('/')
  if (paths[0] === '') {
    paths.shift()
  }
  return paths
}

Sources: src/utils/url.ts:8-14

Group Mark Replacement

Once the path is split into individual segments via splitPath, the replaceGroupMarks function iterates backward through the stored groups to substitute temporary placeholders with their original bracketed definitions.

const replaceGroupMarks = (paths: string[], groups: [string, string][]): string[] => {
  for (let i = groups.length - 1; i >= 0; i--) {
    const [mark] = groups[i]
 
    for (let j = paths.length - 1; j >= 0; j--) {
      if (paths[j].includes(mark)) {
        paths[j] = paths[j].replace(mark, groups[i][1])
        break
      }
    }
  }
 
  return paths
}

Sources: src/utils/url.ts:35-48

Warning

Modifying tokenized path arrays directly without running replaceGroupMarks will leave orphan @index markers intact, corrupting downstream route compilation in RegExp Router and Trie and Smart Routers.

Execution Walkthroughs

Trace Sequences

Extraction Trace
  1. basePath calls splitRoutingPath.
  2. splitRoutingPath calls extractGroupsFromPath.
  3. extractGroupsFromPath matches bracketed expressions and populates the groups array.

Sources: src/helper/route/index.ts:120-120, src/utils/url.ts:16-17, src/utils/url.ts:23-33

Replacement Trace
  1. basePath calls splitRoutingPath.
  2. splitRoutingPath calls splitPath on the cleaned path string.
  3. splitRoutingPath calls replaceGroupMarks to substitute temporary markers.

Sources: src/helper/route/index.ts:120-120, src/utils/url.ts:16-20, src/utils/url.ts:35-48

Was this page helpful?