> ## 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.

# PatternRouter

> Simple router using RegExp patterns for route matching

## Overview

The `PatternRouter` is a straightforward router implementation that converts each route into a regular expression pattern. It's simple, predictable, and supports most common routing patterns without the complexity of trie structures.

## How It Works

The PatternRouter uses a direct approach to routing:

1. **Route Registration**: Each route is converted to a RegExp with named capture groups
2. **Pattern Generation**: Path segments are transformed into regex patterns
3. **Linear Matching**: Routes are tested sequentially until a match is found
4. **Parameter Extraction**: Named groups are extracted from the RegExp match

### Algorithm Details

* Each route stored as a `[RegExp, method, handler]` tuple
* Dynamic parameters (`:name`) become named capture groups: `(?<name>pattern)`
* Optional parameters (`?`) create alternate routes
* Wildcards (`*`) are supported in routes
* Routes matched in registration order (first match wins for same score)
* No preprocessing or optimization

## Performance Characteristics

<CardGroup cols={2}>
  <Card title="Static Routes" icon="gauge">
    **O(n)** - Linear search through all routes
  </Card>

  <Card title="Dynamic Routes" icon="gauge">
    **O(n)** - Tests each route's RegExp sequentially
  </Card>

  <Card title="Build Time" icon="clock">
    **O(1)** - Each route compiled to RegExp immediately
  </Card>

  <Card title="Memory" icon="memory">
    **Low** - One RegExp per route
  </Card>
</CardGroup>

## When to Use

<AccordionGroup>
  <Accordion title="✅ Best For">
    * Small applications with \< 50 routes
    * Simple routing requirements
    * Applications where route order matters
    * Prototypes and proof-of-concepts
    * Learning and understanding routing mechanics
    * When predictable, simple behavior is preferred over performance
  </Accordion>

  <Accordion title="❌ Not Recommended For">
    * Large applications with 100+ routes (consider RegExpRouter)
    * Performance-critical applications
    * High-traffic production APIs
    * Applications with many static routes (no optimization)
  </Accordion>
</AccordionGroup>

## Configuration

To use the PatternRouter, specify it when creating your Hono instance:

```typescript theme={null}
import { Hono } from 'hono'
import { PatternRouter } from 'hono/router/pattern-router'

const app = new Hono({ router: new PatternRouter() })
```

## Usage Examples

### Basic Routing

```typescript theme={null}
import { Hono } from 'hono'
import { PatternRouter } from 'hono/router/pattern-router'

const app = new Hono({ router: new PatternRouter() })

// Static routes
app.get('/', (c) => c.text('Home'))
app.get('/about', (c) => c.text('About'))
app.get('/contact', (c) => c.text('Contact'))

// Dynamic routes with parameters
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ userId: id })
})

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

### Parameter Patterns

```typescript theme={null}
// Parameter with RegExp constraint
app.get('/users/:id{[0-9]+}', (c) => {
  const id = c.req.param('id')  // Guaranteed to be numeric
  return c.json({ userId: parseInt(id) })
})

// Complex pattern matching
app.get('/files/:filename{.+\\.(jpg|png|gif)}', (c) => {
  const filename = c.req.param('filename')
  return c.json({ file: filename })
})

// Pattern with multiple constraints
app.get('/api/:version{v[1-9]+}/:resource', (c) => {
  const { version, resource } = c.req.param()
  return c.json({ version, resource })
})
```

### Optional Parameters

```typescript theme={null}
// Optional trailing parameter
app.get('/docs/:page?', (c) => {
  const page = c.req.param('page') || 'index'
  return c.json({ page })
})

// Optional parameter in path
app.get('/api/v1/users/:id?', (c) => {
  const id = c.req.param('id')
  if (id) {
    return c.json({ user: id })
  }
  return c.json({ users: 'all' })
})

// Multiple optional segments
app.get('/blog/:year?/:month?/:day?', (c) => {
  const { year, month, day } = c.req.param()
  return c.json({ year, month, day })
})
```

### Wildcard Routes

```typescript theme={null}
// Trailing wildcard
app.get('/static/*', (c) => {
  return c.text('Static file handler')
})

// Wildcard matches rest of path
app.get('/files/public/*', (c) => {
  return c.text('Public files')
})

// Without trailing slash
app.get('/api/v1/*', (c) => {
  return c.json({ api: 'v1', path: c.req.path })
})
```

### Route Order Matters

```typescript theme={null}
// ✅ Correct order: Specific routes first
app.get('/users/me', (c) => c.json({ user: 'current' }))
app.get('/users/:id', (c) => c.json({ user: c.req.param('id') }))
// GET /users/me → matches first route ✓

// ❌ Wrong order: Generic route shadows specific
app.get('/users/:id', (c) => c.json({ user: c.req.param('id') }))
app.get('/users/me', (c) => c.json({ user: 'current' }))
// GET /users/me → matches first route as :id = "me" ✗
```

## How Pattern Matching Works

### Pattern Conversion

```typescript theme={null}
// Route: '/users/:id/posts/:postId'
// Becomes RegExp: /^\/users\/(?<id>[^/]+)\/posts\/(?<postId>[^/]+)\/?$/

// Route: '/files/:name{[a-z]+.txt}'
// Becomes RegExp: /^\/files\/(?<name>[a-z]+\.txt)\/?$/

// Route: '/api/*'
// Becomes RegExp: /^\/api\//
```

### Matching Process

```typescript theme={null}
// Conceptual matching algorithm
function match(method: string, path: string) {
  const handlers = []
  
  for (const [pattern, routeMethod, handler] of routes) {
    if (routeMethod === method || routeMethod === 'ALL') {
      const match = pattern.exec(path)
      if (match) {
        handlers.push([handler, match.groups || {}])
      }
    }
  }
  
  return [handlers]
}
```

### Example Flow

```typescript theme={null}
app.get('/api/users', handler1)
app.get('/api/:resource', handler2)
app.get('/api/*', handler3)

// Request: GET /api/users
// 1. Test /^\/api\/users\/?$/  → ✓ match → add handler1
// 2. Test /^\/api\/(?<resource>[^/]+)\/?$/ → ✓ match → add handler2
// 3. Test /^\/api\// → ✓ match → add handler3
// Returns: [handler1, handler2, handler3] with appropriate params
```

## Advanced Features

### Custom Pattern Syntax

PatternRouter supports custom RegExp patterns within parameters:

```typescript theme={null}
// Numeric IDs only
app.get('/items/:id{[0-9]+}', handler)

// Slugs (lowercase, hyphens)
app.get('/posts/:slug{[a-z0-9-]+}', handler)

// Date format (YYYY-MM-DD)
app.get('/events/:date{\\d{4}-\\d{2}-\\d{2}}', handler)

// UUID format
app.get('/resources/:uuid{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}', handler)
```

### Nested Parameters

```typescript theme={null}
// Deep nesting is supported
app.get('/:org/projects/:project/issues/:issue', (c) => {
  const { org, project, issue } = c.req.param()
  return c.json({ org, project, issue })
})

// Mix of static and dynamic
app.get('/:tenant/api/v1/resources/:id', (c) => {
  const { tenant, id } = c.req.param()
  return c.json({ tenant, resourceId: id })
})
```

### Trailing Slashes

PatternRouter automatically handles trailing slashes:

```typescript theme={null}
app.get('/users/:id', handler)

// Both match:
// GET /users/123   ✓
// GET /users/123/  ✓
```

## Limitations

<Warning>
  PatternRouter has some limitations:

  * **Linear performance**: O(n) for all route types
  * **No optimization**: Static routes not faster than dynamic
  * **Order dependent**: Route registration order matters
  * **No route conflict detection**: Overlapping patterns silently return multiple handlers
</Warning>

### Unsupported Patterns

```typescript theme={null}
// ❌ These may throw UnsupportedPathError or behave unexpectedly:

// Invalid RegExp patterns
app.get('/users/:id{[invalid}', handler)  // Throws during route registration

// Extremely complex patterns may fail
app.get('/complex/:param{(?:..very long pattern..)}', handler)
```

## Performance Optimization Tips

<Tip>
  Optimize PatternRouter performance:

  1. **Put common routes first** - They'll match faster
  2. **Minimize total routes** - Each route is tested sequentially
  3. **Use specific patterns** - Reduce false matches
  4. **Group by method** - Method check happens before pattern matching
</Tip>

### Optimization Example

```typescript theme={null}
// ✅ Optimized: Most common routes first
app.get('/', homeHandler)              // Most traffic
app.get('/about', aboutHandler)        // Second most
app.get('/contact', contactHandler)    // Third
app.get('/users/:id', userHandler)     // Less common
app.get('/*', notFoundHandler)         // Catch-all last

// ❌ Not optimized: Catch-all first
app.get('/*', catchAll)                // Matches everything!
app.get('/', homeHandler)              // Never reached
```

## Comparison with Other Routers

| Feature         | PatternRouter | RegExpRouter | TrieRouter | LinearRouter |
| --------------- | ------------- | ------------ | ---------- | ------------ |
| Static routes   | O(n)          | O(1)         | O(n)       | O(n)         |
| Dynamic routes  | O(n)          | O(1)         | O(n×m)     | O(n)         |
| Pattern support | Good          | Limited      | Excellent  | Excellent    |
| Memory usage    | Low           | High         | Medium     | Low          |
| Simplicity      | High          | Low          | Medium     | High         |
| Build time      | O(1)          | O(n log n)   | O(1)       | O(1)         |

## Internal Architecture

### Route Storage

```typescript theme={null}
class PatternRouter<T> {
  name = 'PatternRouter'
  #routes: [RegExp, string, T][] = []  // [pattern, method, handler]
}
```

### Add Method

```typescript theme={null}
// Simplified add logic
add(method: string, path: string, handler: T) {
  // Handle wildcards
  const endsWithWildcard = path.endsWith('*')
  
  // Handle optional parameters
  if (path.endsWith('?')) {
    // Creates additional route without optional part
  }
  
  // Convert path to RegExp pattern
  const parts = path.match(/\/?(:\w+(?:{[^}]+})?)|\/?[^\/\?]+/g)
  const pattern = parts.map(convertToRegex).join('')
  
  // Store compiled pattern
  this.#routes.push([new RegExp(pattern), method, handler])
}
```

## Debugging Routes

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

app.get('/users/:id', handler)

// Access internal routes (for debugging only!)
console.log(router.routes)  // Array of [RegExp, method, handler]
```

## Source Code Reference

The PatternRouter implementation can be found at:

* Router: `src/router/pattern-router/router.ts`

## See Also

<CardGroup cols={2}>
  <Card title="LinearRouter" icon="list" href="/api/routers/linear-router">
    Simple router without RegExp compilation
  </Card>

  <Card title="RegExpRouter" icon="wand-magic-sparkles" href="/api/routers/regexp-router">
    High-performance compiled router
  </Card>

  <Card title="Routing Guide" icon="route" href="/routing/routers">
    Learn about choosing the right router
  </Card>

  <Card title="Route Parameters" icon="tag" href="/routing/route-parameters">
    Working with dynamic parameters
  </Card>
</CardGroup>
