---
title: "Trie and Smart Routers"
description: "Hono's TrieRouter and SmartRouter deliver hierarchical prefix routing and dynamic dispatch across multiple matching backends. TrieRouter manages route registration through tree node insertion, supp..."
last_updated: "2026-10-12T08:14:12.747835+00:00"
canonical_url: "https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/routing/trie-and-smart-routers"
---

<details>
<summary>Relevant source files</summary>

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

- [src/router/smart-router/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts)
- [src/router/trie-router/node.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts)
- [src/router/trie-router/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/index.ts)
- [src/helper/route/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/route/index.ts)
- [src/router/trie-router/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts)
- [src/types.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/types.ts)
- [src/preset/quick.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/preset/quick.ts)
- [src/router/reg-exp-router/prepared-router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/prepared-router.ts)
- [src/router/linear-router/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/linear-router/router.ts)
- [src/router/reg-exp-router/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/router.ts)
- [src/router/reg-exp-router/node.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/node.ts)
- [src/middleware/ip-restriction/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/ip-restriction/index.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/hono.ts)
- [src/router/reg-exp-router/trie.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/trie.ts)
- [src/router/reg-exp-router/matcher.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/matcher.ts)
- [src/middleware/language/language.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/language/language.ts)
- [src/utils/url.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/utils/url.ts)
- [src/router/smart-router/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/index.ts)
- [src/helper/dev/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/dev/index.ts)
- [src/router/pattern-router/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/pattern-router/router.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/hono-base.ts)
- [src/utils/ipaddr.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/utils/ipaddr.ts)
- [package.json](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/package.json)
- [src/preset/tiny.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/preset/tiny.ts)
- [src/router.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router.ts)
- [src/router/linear-router/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/linear-router/index.ts)
- [src/helper/ssg/utils.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/ssg/utils.ts)
- [src/helper/adapter/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/adapter/index.ts)
- [src/router/reg-exp-router/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/reg-exp-router/index.ts)
- [src/router/pattern-router/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/pattern-router/index.ts)
</details>

## Overview

Hono's `TrieRouter` and `SmartRouter` deliver hierarchical prefix routing and dynamic dispatch across multiple matching backends. `TrieRouter` manages route registration through tree node insertion, supporting optional parameter expansion, path segment tokenization, and recursive handler set collection. To combine different routing strategies, `SmartRouter` aggregates multiple router instances, delegating registration to each candidate until a successful match occurs and locking onto the winning backend for subsequent requests. Sources: [src/router/smart-router/router.ts:4-70](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L4-L70), [src/router/trie-router/node.ts:25-112](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L25-L112), [src/router/trie-router/router.ts:5-27](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts#L5-L27)

## TrieRouter Architecture and Route Registration

### Public Interface and Root Node Management

`TrieRouter<T>` implements the unified `Router<T>` interface, identifying itself via the `name` property set to `'TrieRouter'`. The class initializes a private root `#node` instance of type `Node<T>` inside its constructor to anchor the entire route prefix tree.

```typescript
export class TrieRouter<T> implements Router<T> {
  name: string = 'TrieRouter'
  #node: Node<T>

  constructor() {
    this.#node = new Node()
  }
...
```
Sources: [src/router/trie-router/router.ts:5-11](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts#L5-L11)

### Optional Parameter Expansion and Route Insertion

When adding routes through the `add(method, path, handler)` method, `TrieRouter` inspects the incoming route path using `checkOptionalParameter(path)`. If optional parameters are present, the utility returns an array of expanded path variations; the router iterates over these results and inserts each individual variation into the root node. If no optional parameters are detected, the path is inserted directly.

```typescript
  add(method: string, path: string, handler: T) {
    const results = checkOptionalParameter(path)
    if (results) {
      for (let i = 0, len = results.length; i < len; i++) {
        this.#node.insert(method, results[i], handler)
      }
      return
    }

    this.#node.insert(method, path, handler)
  }
```
Sources: [src/router/trie-router/router.ts:13-23](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts#L13-L23)

> [!NOTE]
> `checkOptionalParameter` handles path patterns containing optional segments by generating all possible route combinations, ensuring each variant is separately registered in the prefix tree.

Sources: [src/router/trie-router/router.ts:14-20](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts#L14-L20)

### Route Matching Delegation

Incoming request matching delegates execution directly to the root node's `search` method, forwarding both the HTTP `method` and request `path` and returning a resolved `Result<T>` structure containing matched handlers and captured parameters.

```typescript
  match(method: string, path: string): Result<T> {
    return this.#node.search(method, path)
  }
```
Sources: [src/router/trie-router/router.ts:25-27](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/router.ts#L25-L27)

## Trie Node Structure and Insertion

### Node Fields and Constructor Initialization

The `Node<T>` class maintains the internal state of the prefix tree using private fields. Each node tracks its registered methods, child nodes, extracted routing patterns, insertion order counters, and parameter records.

```typescript
export class Node<T> {
  #methods: Record<string, HandlerSet<T>>[]

  #children: Record<string, Node<T>>
  #patterns: Pattern[]
  #order: number = 0
  #params: Record<string, string> = emptyParams

  constructor(method?: string, handler?: T, children?: Record<string, Node<T>>) {
    this.#children = children || Object.create(null)
    this.#methods = []
    if (method && handler) {
      const m: Record<string, HandlerSet<T>> = Object.create(null)
      m[method] = { handler, possibleKeys: [], score: 0 }
      this.#methods = [m]
    }
    this.#patterns = []
  }
```
Sources: [src/router/trie-router/node.ts:25-42](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L25-L42)

> [!NOTE]
> `emptyParams` is initialized via `Object.create(null)` to provide a prototype-free parameter dictionary.

Sources: [src/router/trie-router/node.ts:16-16](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L16-L16)

### Path Segment Tokenization and Pattern Extraction

During route insertion, `insert(method, path, handler)` increments the node order counter and splits the routing path into individual segments using `splitRoutingPath(path)`. It iterates through each segment, calling `getPattern(p, nextP)` to extract parameter and wildcard patterns.

```typescript
insert(method: string, path: string, handler: T): Node<T> {
  this.#order = ++this.#order

  // eslint-disable-next-line @typescript-eslint/no-this-alias
  let curNode: Node<T> = this
  const parts = splitRoutingPath(path)

  const possibleKeys: string[] = []

  for (let i = 0, len = parts.length; i < len; i++) {
    const p: string = parts[i]
    const nextP = parts[i + 1]
    const pattern = getPattern(p, nextP)
    const key = Array.isArray(pattern) ? pattern[0] : p

    if (key in curNode.#children) {
      curNode = curNode.#children[key]
      if (pattern) {
        possibleKeys.push(pattern[1])
      }
      continue
    }
```
Sources: [src/router/trie-router/node.ts:44-65](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L44-L65)

### Recursive Tree Construction and Handler Binding

If a segment key already exists within `curNode.#children`, traversal descends into that child node. Otherwise, a new `Node` instance is instantiated and registered. Extracted patterns are pushed to `#patterns`, and final handler sets are appended to `#methods` with deduplicated `possibleKeys` and an insertion order score.

```typescript

    curNode.#children[key] = new Node()

    if (pattern) {
      curNode.#patterns.push(pattern)
      possibleKeys.push(pattern[1])
    }
    curNode = curNode.#children[key]
  }

  curNode.#methods.push({
    [method]: {
      handler,
      possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
      score: this.#order,
    },
  })

  return curNode
}
```
Sources: [src/router/trie-router/node.ts:66-85](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L66-L85)

> [!WARNING]
> Handler sets filter `possibleKeys` using `a.indexOf(v) === i` to prevent duplicate parameter keys within the same handler registration block.

Sources: [src/router/trie-router/node.ts:76-82](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L76-L82)

## Hierarchical Path Traversal and Matching

### Recursive Search Execution and Queue Management

Path lookup begins by invoking `search(method, path)` on the root node, which splits the request path using `splitPath(path)` and initializes a traversal queue of active nodes (`curNodes`) alongside `curNodesQueue` for handling multi-segment regular expression parameter matches.

```typescript
search(method: string, path: string): [[T, Params][]] {
  const handlerSets: HandlerParamsSet<T>[] = []
  this.#params = emptyParams

  // eslint-disable-next-line @typescript-eslint/no-this-alias
  const curNode: Node<T> = this
  let curNodes = [curNode]
  const parts = splitPath(path)
  const curNodesQueue: Node<T>[][] = []

  const len = parts.length
  let partOffsets: number[] | null = null

```
Sources: [src/router/trie-router/node.ts:114-126](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L114-L126)

### Static Child Lookup and Wildcard Handling

During iteration over path segments, the router checks static child nodes via `node.#children[part]`. When reaching the final path segment on a matching child, it evaluates trailing wildcard children (`nextNode.#children['*']`) and pushes matching handler sets into the accumulation array.

```typescript
for (let i = 0; i < len; i++) {
  const part: string = parts[i]
  const isLast = i === len - 1
  const tempNodes: Node<T>[] = []

  for (let j = 0, len2 = curNodes.length; j < len2; j++) {
    const node = curNodes[j]
    const nextNode = node.#children[part]

    if (nextNode) {
      nextNode.#params = node.#params
      if (isLast) {
        // '/hello/*' => match '/hello'
        if (nextNode.#children['*']) {
          this.#pushHandlerSets(handlerSets, nextNode.#children['*'], method, node.#params)
        }
        this.#pushHandlerSets(handlerSets, nextNode, method, node.#params)
      } else {
        tempNodes.push(nextNode)
      }
    }

```
Sources: [src/router/trie-router/node.ts:127-148](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L127-L148)

> [!NOTE]
> Wildcard patterns (`*`) directly inspect child nodes keyed by `*`, pushing their associated handler sets and enqueuing the wildcard astNode for subsequent path segments.

Sources: [src/router/trie-router/node.ts:153-163](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L153-L163)

### Parameter Capture and Regular Expression Matchers

Nodes with patterns evaluate parameters and regular expressions against the remaining path string using precomputed part offsets. If a regular expression matcher succeeds, captured values populate the parameters dictionary and child nodes are scheduled via `curNodesQueue`.

```typescript
const [key, name, matcher] = pattern

if (!part && !(matcher instanceof RegExp)) {
  continue
}

const child = node.#children[key]

// `/js/:filename{[a-z]+.js}` => match /js/chunk/123.js
if (matcher instanceof RegExp) {
  if (partOffsets === null) {
    partOffsets = new Array(len)
    let offset = path[0] === '/' ? 1 : 0
    for (let p = 0; p < len; p++) {
      partOffsets[p] = offset
      offset += parts[p].length + 1
    }
  }
  const restPathString = path.substring(partOffsets[i])

  const m = matcher.exec(restPathString)
  if (m) {
    params[name] = m[0]
    this.#pushHandlerSets(handlerSets, child, method, node.#params, params)

    if (hasChildren(child.#children)) {
      child.#params = params
      const componentCount = m[0].match(/\//)?.length ?? 0
      const targetCurNodes = (curNodesQueue[componentCount] ||= [])
      targetCurNodes.push(child)
    }

    continue
  }
}

if (matcher === true || matcher.test(part)) {
  params[name] = part
  if (isLast) {
```
Sources: [src/router/trie-router/node.ts:165-203](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L165-L203)

### Handler Set Collection

The `#pushHandlerSets` helper method resolves method-specific handlers or `METHOD_NAME_ALL` fallbacks, binds parameter dictionaries from `possibleKeys`, and populates the output `handlerSets` collection.

```typescript
#pushHandlerSets(
  handlerSets: HandlerParamsSet<T>[],
  node: Node<T>,
  method: string,
  nodeParams: Record<string, string>,
  params?: Record<string, string>
): void {
  for (let i = 0, len = node.#methods.length; i < len; i++) {
    const m = node.#methods[i]
    const handlerSet = (m[method] || m[METHOD_NAME_ALL]) as HandlerParamsSet<T>
    const processedSet: Record<number, boolean> = {}
    if (handlerSet !== undefined) {
      handlerSet.params = Object.create(null)
      handlerSets.push(handlerSet)
      if (nodeParams !== emptyParams || (params && params !== emptyParams)) {
        for (let i = 0, len = handlerSet.possibleKeys.length; i < len; i++) {
          const key = handlerSet.possibleKeys[i]
          const processed = processedSet[handlerSet.score]
          handlerSet.params[key] =
            params?.[key] && !processed ? params[key] : (nodeParams[key] ?? params?.[key])
          processedSet[handlerSet.score] = true
        }
      }
    }
  }
}
```
Sources: [src/router/trie-router/node.ts:87-112](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L87-L112)

> [!WARNING]
> Parameter inheritance checks `nodeParams` against `params` using `processedSet` deduplication flags to ensure route parameters maintain correct scope across hierarchical child transitions.

Sources: [src/router/trie-router/node.ts:97-110](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/trie-router/node.ts#L97-L110)

## SmartRouter Architecture and Routing Backends

### Multi-Router Aggregation and Registration Contract

The `SmartRouter<T>` class implements the unified `Router<T>` interface by aggregating an array of candidate router backends via its constructor initialization parameter (`init.routers`). During the registration phase, calling `add(method, path, handler)` pushes route tuples `[method, path, handler]` into the internal `#routes` collection. If route addition is attempted after the matcher has already been built, it throws an error with the message defined by `MESSAGE_MATCHER_IS_ALREADY_BUILT`.

```typescript
export class SmartRouter<T> implements Router<T> {
  name: string = 'SmartRouter'
  #routers: Router<T>[] = []
  #routes?: [string, string, T][] = []

  constructor(init: { routers: Router<T>[] }) {
    this.#routers = init.routers
  }

  add(method: string, path: string, handler: T) {
    if (!this.#routes) {
      throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT)
    }

    this.#routes.push([method, path, handler])
  }

```
Sources: [src/router/smart-router/router.ts:4-20](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L4-L20)

> [!WARNING]
> Calling `add()` after matching has been evaluated throws an error because `#routes` is set to `undefined` once an active router locks in.

Sources: [src/router/smart-router/router.ts:13-19](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L13-L19), [src/router/smart-router/router.ts:48-48](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L48-L48)

### Routing Delegation and Matcher Locking

When `match(method, path)` is invoked, `SmartRouter` iterates through the candidate routers in `#routers`, populating each candidate with all accumulated routes from `#routes` and testing them sequentially. If an `UnsupportedPathError` occurs on a candidate router, the loop catches the exception, ignores it with `continue`, and falls back to the next available router backend. 

```typescript
match(method: string, path: string): Result<T> {
  if (!this.#routes) {
    throw new Error('Fatal error')
  }

  const routers = this.#routers
  const routes = this.#routes

  const len = routers.length
  let i = 0
  let res
  for (; i < len; i++) {
    const router = routers[i]
    try {
      for (let i = 0, len = routes.length; i < len; i++) {
        router.add(...routes[i])
      }
      res = router.match(method, path)
    } catch (e) {
      if (e instanceof UnsupportedPathError) {
        continue
      }
      throw e
    }

    this.match = router.match.bind(router)
    this.#routers = [router]
    this.#routes = undefined
    break
  }

```
Sources: [src/router/smart-router/router.ts:21-51](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L21-L51)

> [!TIP]
> Upon a successful match, `SmartRouter` mutates its own prototype methods and state by binding `this.match` directly to the winning `router.match`, reducing `#routers` to a single-element array containing the active router, and clearing `#routes`.

Sources: [src/router/smart-router/router.ts:46-49](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L46-L49)

### Router State Properties

| Property / Method | Type / Signature | Description |
| :--- | :--- | :--- |
| `name` | `string` | Identifies the router name, initialized as `'SmartRouter'` and updated to include the active router name post-selection (e.g. `SmartRouter + RegExpRouter`). |
| `#routers` | `Router<T>[]` | Internal array of candidate routing backends provided at instantiation, narrowing down to the single active router upon successful execution. |
| `#routes` | `[string, string, T][] \| undefined` | Temporary storage holding registered route tuples before matcher locking; set to `undefined` once a router successfully handles a match. |
| `activeRouter` | `Router<T>` | Getter returning the single active router instance once routing has locked in, throwing an error if routes are still pending or multiple routers remain. |

```typescript
export class SmartRouter<T> implements Router<T> {
  name: string = 'SmartRouter'
  #routers: Router<T>[] = []
  #routes?: [string, string, T][] = []

  constructor(init: { routers: Router<T>[] }) {
    this.#routers = init.routers
  }
```
Sources: [src/router/smart-router/router.ts:4-11](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L4-L11), [src/router/smart-router/router.ts:63-69](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L63-L69)

## Dynamic Router Selection and Fallback

### Heuristic Selection on First Match

`SmartRouter` resolves which underlying router backend handles incoming traffic dynamically during the initial call to `match(method, path)`. It iterates through each candidate router in `#routers`, replaying all buffered route tuples from `#routes` into the candidate via its `add()` method, and immediately attempts to match the target request. If a candidate router successfully executes the match without throwing an `UnsupportedPathError` or other exceptions, selection halts immediately via a `break` statement.

```typescript
const routers = this.#routers
const routes = this.#routes

const len = routers.length
let i = 0
let res
for (; i < len; i++) {
  const router = routers[i]
  try {
    for (let i = 0, len = routes.length; i < len; i++) {
      router.add(...routes[i])
    }
    res = router.match(method, path)
  } catch (e) {
    if (e instanceof UnsupportedPathError) {
      continue
    }
    throw e
  }

  this.match = router.match.bind(router)
  this.#routers = [router]
  this.#routes = undefined
  break
}
```
Sources: [src/router/smart-router/router.ts:26-50](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L26-L50)

> [!WARNING]
> If all candidate routers fail to match or throw unhandled exceptions, the outer loop completes without breaking (`i === len`), triggering a fatal error throw that halts execution.

Sources: [src/router/smart-router/router.ts:52-55](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L52-L55)

### UnsupportedPathError Handling and Matcher Locking

During heuristic evaluation, candidate routers may encounter path syntax or expression structures they cannot process, throwing an `UnsupportedPathError`. The `try...catch` block inspects caught errors; if `e instanceof UnsupportedPathError` is true, the error is suppressed, and execution continues to the next candidate router in the sequence. Any other error type is rethrown immediately.

```typescript
try {
  for (let i = 0, len = routes.length; i < len; i++) {
    router.add(...routes[i])
  }
  res = router.match(method, path)
} catch (e) {
  if (e instanceof UnsupportedPathError) {
    continue
  }
  throw e
}
```
Sources: [src/router/smart-router/router.ts:34-44](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L34-L44)

> [!TIP]
> Once a candidate successfully matches, `SmartRouter` locks its matcher by reassigning `this.match` to bind directly to the winning `router.match`, collapsing `#routers` to a single-element array containing only the active router, setting `#routes` to `undefined`, and updating `this.name` to reflect the active backend (e.g., `SmartRouter + RegExpRouter`). Subsequent requests bypass heuristic iteration entirely.

Sources: [src/router/smart-router/router.ts:46-58](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/router/smart-router/router.ts#L46-L58)

## Related

- [Router Contracts](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/routing/router-contracts)
- [RegExp Router](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/routing/regexp-router)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
