> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# Route Parameters

> Learn how to use dynamic route parameters and wildcards in Hono

## Path Parameters

Route parameters allow you to capture dynamic segments from the URL path using the `:param` syntax:

```typescript theme={null}
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.text(`User ID: ${id}`)
})

// GET /users/123 -> "User ID: 123"
// GET /users/john -> "User ID: john"
```

## Getting All Parameters

You can retrieve all parameters at once as an object:

```typescript theme={null}
app.get('/posts/:id/comments/:commentId', (c) => {
  const { id, commentId } = c.req.param()
  return c.json({ postId: id, commentId })
})

// GET /posts/123/comments/456
// -> {"postId": "123", "commentId": "456"}
```

From `src/request.ts:102`, the `param()` method can be called with or without a key:

```typescript theme={null}
param(key?: string): unknown {
  return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams()
}
```

## URL Decoding

Parameters are automatically URL-decoded:

```typescript theme={null}
app.get('/entry/:id', (c) => {
  const id = c.req.param('id')
  return c.text(`ID: ${id}`)
})

// GET /entry/%C3%A7awa%20y%C3%AE%3F
// -> "ID: çawa yî?"
```

The decoding logic in `src/request.ts:109` handles this automatically:

```typescript theme={null}
#getDecodedParam(key: string): string | undefined {
  const paramKey = this.#matchResult[0][this.routeIndex][1][key]
  const param = this.#getParamValue(paramKey)
  return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param
}
```

## Multiple Parameters

You can have multiple parameters in a single route:

```typescript theme={null}
app.get('/users/:userId/posts/:postId/comments/:commentId', (c) => {
  const { userId, userId, commentId } = c.req.param()
  return c.json({ userId, postId, commentId })
})
```

## Optional Parameters

Mark parameters as optional by adding a `?` after the segment:

```typescript theme={null}
app.get('/posts/:id/comments?', (c) => {
  return c.text('Post with optional comments path')
})

// GET /posts/123 -> Matches
// GET /posts/123/comments -> Matches
```

<Note>
  Optional parameters are handled by the router during route registration, creating multiple route entries.
</Note>

The `checkOptionalParameter` utility in `src/utils/url.ts` handles this:

```typescript theme={null}
// From src/router/linear-router/router.ts:16
for (
  let i = 0, paths = checkOptionalParameter(path) || [path], len = paths.length;
  i < len;
  i++
) {
  this.#routes.push([method, paths[i], handler])
}
```

## Pattern Constraints

Use regular expressions to constrain parameter values:

```typescript theme={null}
// Only match numeric IDs
app.get('/users/:id{[0-9]+}', (c) => {
  const id = c.req.param('id')
  return c.text(`User ID: ${id}`)
})

// GET /users/123 -> Matches
// GET /users/abc -> Does not match

// Date format
app.get('/date/:date{[0-9]{4}-[0-9]{2}-[0-9]{2}}', (c) => {
  const date = c.req.param('date')
  return c.text(`Date: ${date}`)
})

// GET /date/2024-01-15 -> Matches
// GET /date/invalid -> Does not match
```

From `src/router/pattern-router/router.ts:24`, patterns are converted to regex:

```typescript theme={null}
const match = part.match(/^\/:([^{]+)(?:{(.*)})?/)
return match
  ? `/(?<${match[1]}>${match[2] || '[^/]+'})`
  : part === '/*'
    ? '/[^/]+'
    : part.replace(/[.\\+*[^\]$()]/g, '\\$&')
```

## Wildcard Parameters

The `*` wildcard matches any path segment(s):

```typescript theme={null}
// Match any subpath
app.get('/api/*', (c) => {
  return c.text('API route')
})

// GET /api/users -> Matches
// GET /api/users/123 -> Matches
// GET /api/v1/users/123 -> Matches
```

### Combining Parameters with Wildcards

```typescript theme={null}
app.get('/users/:id/*', (c) => {
  const id = c.req.param('id')
  return c.text(`User ${id} subpath`)
})

// GET /users/123/profile -> "User 123 subpath"
// GET /users/123/settings/privacy -> "User 123 subpath"
```

## Catch-All Routes

A single `*` catches all routes:

```typescript theme={null}
app.get('*', (c) => {
  return c.text('404 Not Found', 404)
})
```

<Warning>
  Wildcard routes should typically be defined last, as they match broadly.
</Warning>

## Parameter Matching Behavior

The router implementation determines how parameters are matched. From the router interface in `src/router.ts:51`:

```typescript theme={null}
export interface Router<T> {
  name: string
  add(method: string, path: string, handler: T): void
  match(method: string, path: string): Result<T>
}
```

### Match Result Structure

The result of matching includes handlers and their parameter mappings:

```typescript theme={null}
// From src/router.ts:76
// Example result format:
[
  [
    [middlewareA, {}],                             // '*'
    [funcA,       {'id': '123'}],                  // '/user/:id/*'
    [funcB,       {'id': '123', 'action': 'abc'}], // '/user/:id/:action'
  ]
]
```

## Router-Specific Behavior

Different routers handle parameters with varying performance characteristics:

* **RegExpRouter**: Builds regex patterns for efficient matching
* **TrieRouter**: Uses a trie data structure for prefix matching
* **LinearRouter**: Iterates through routes sequentially
* **PatternRouter**: Uses regex with named capture groups

## Type Safety

With TypeScript, Hono provides type-safe parameter access:

```typescript theme={null}
const app = new Hono()

const route = app.get('/users/:id', (c) => {
  const id = c.req.param('id') // Type: string
  return c.json({ id })
})

// The route type includes parameter information
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use descriptive parameter names">
    Choose parameter names that clearly indicate their purpose:

    ```typescript theme={null}
    // Good
    app.get('/users/:userId/posts/:postId', handler)

    // Avoid
    app.get('/users/:id/posts/:id2', handler)
    ```
  </Accordion>

  <Accordion title="Validate parameter values">
    Use pattern constraints or validation middleware:

    ```typescript theme={null}
    app.get('/users/:id{[0-9]+}', (c) => {
      const id = c.req.param('id')
      // id is guaranteed to be numeric
      return c.json({ id: parseInt(id) })
    })
    ```
  </Accordion>

  <Accordion title="Handle missing parameters gracefully">
    Always check for undefined when accessing optional parameters:

    ```typescript theme={null}
    app.get('/search', (c) => {
      const query = c.req.param('q') || 'default'
      return c.text(`Searching for: ${query}`)
    })
    ```
  </Accordion>
</AccordionGroup>
