Skip to main content
The Route helper provides utilities for inspecting matched routes and retrieving route path information during request handling. This is useful for logging, debugging, and dynamic routing logic.

Import

import { matchedRoutes, routePath, baseRoutePath, basePath } from 'hono/route'

Getting Matched Routes

matchedRoutes

Retrieve all routes that matched the current request, including middleware and handlers:
import { matchedRoutes } from 'hono/route'

app.use('*', async (c, next) => {
  await next()
  
  matchedRoutes(c).forEach(({ handler, method, path }, i) => {
    const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
    console.log(
      method,
      ' ',
      path,
      ' '.repeat(Math.max(10 - path.length, 0)),
      name,
      i === c.req.routeIndex ? '<- respond from here' : ''
    )
  })
})
Returns: RouterRoute[] - Array of matched route objects containing:
  • path: The route pattern (e.g., /posts/:id)
  • method: HTTP method (e.g., GET, POST)
  • handler: The handler function
  • basePath: The base path of the route
The routes are returned in the order they were matched, with middleware first followed by the final handler.

Getting Route Paths

routePath

Get the route pattern that was registered for the current request:
import { routePath } from 'hono/route'

app.use('*', (c, next) => {
  console.log(routePath(c))     // '*'
  console.log(routePath(c, -1)) // '/posts/:id'
  return next()
})

app.get('/posts/:id', (c) => {
  return c.text(routePath(c)) // '/posts/:id'
})
Parameters:
c
Context
required
The Hono context object
index
number
The index of the route to retrieve. Supports negative indices (counted from the end). Defaults to the current route index.
Returns: string - The route pattern, or empty string if index is out of bounds

baseRoutePath

Get the raw base path of the route as registered, including any parameters:
import { baseRoutePath } from 'hono/route'

const app = new Hono()

const subApp = new Hono()
subApp.get('/posts/:id', (c) => {
  return c.text(baseRoutePath(c)) // '/:sub'
})

app.route('/:sub', subApp)
Parameters:
c
Context
required
The Hono context object
index
number
The index of the route to retrieve. Supports negative indices. Defaults to the current route index.
Returns: string - The raw base path with parameter placeholders

basePath

Get the actual base path with parameter values filled in:
import { basePath } from 'hono/route'

const app = new Hono()

const subApp = new Hono()
subApp.get('/posts/:id', (c) => {
  return c.text(basePath(c)) // '/api' (if request was to /api/posts/123)
})

app.route('/:sub', subApp)
Parameters:
c
Context
required
The Hono context object
index
number
The index of the route to retrieve. Supports negative indices. Defaults to the current route index.
Returns: string - The resolved base path with actual parameter values
basePath results are cached for performance. The function intelligently resolves parameter values from the actual request path.

Use Cases

Request Logging

Log all matched routes for debugging:
import { matchedRoutes } from 'hono/route'

app.use('*', async (c, next) => {
  const start = Date.now()
  await next()
  const ms = Date.now() - start
  
  const routes = matchedRoutes(c)
  console.log(`${c.req.method} ${c.req.path} - ${ms}ms - ${routes.length} handlers`)
})

Dynamic Routing Logic

Implement logic based on the current route:
import { routePath } from 'hono/route'

app.get('/api/*', (c) => {
  const pattern = routePath(c)
  
  if (pattern === '/api/*') {
    return c.json({ error: 'Not found' }, 404)
  }
  
  return c.json({ path: pattern })
})

Sub-application Context

Determine which sub-application is handling the request:
import { basePath } from 'hono/route'

const apiApp = new Hono()
apiApp.get('/users', (c) => {
  const base = basePath(c) // '/api/v1'
  return c.json({ base, message: 'Users endpoint' })
})

app.route('/api/v1', apiApp)

Accessing Previous Middleware Routes

Inspect which middleware have already run:
import { routePath } from 'hono/route'

app.use('/admin/*', authMiddleware)

app.get('/admin/users', (c) => {
  // Get the middleware route pattern
  const middlewarePath = routePath(c, 0) // '/admin/*'
  const handlerPath = routePath(c, 1)    // '/admin/users'
  
  return c.json({ middlewarePath, handlerPath })
})

Understanding Route Index

The index parameter works similar to Array.prototype.at():
import { routePath } from 'hono/route'

// Assuming routes: ['*', '/api/*', '/api/users']

app.get('/api/users', (c) => {
  routePath(c)     // Current route: '/api/users'
  routePath(c, 0)  // First route: '*'
  routePath(c, 1)  // Second route: '/api/*'
  routePath(c, 2)  // Third route: '/api/users'
  routePath(c, -1) // Last route: '/api/users'
  routePath(c, -2) // Second to last: '/api/*'
  routePath(c, 99) // Out of bounds: ''
})

Best Practices

Use for Logging

Perfect for request logging and debugging matched routes

Cache Aware

basePath caches results automatically for optimal performance

Middleware Inspection

Use matchedRoutes to inspect the entire middleware chain

Negative Indices

Use negative indices to access routes from the end of the match list

Type Definitions

interface RouterRoute {
  path: string
  method: string
  handler: Function
  basePath: string
}

function matchedRoutes(c: Context): RouterRoute[]
function routePath(c: Context, index?: number): string
function baseRoutePath(c: Context, index?: number): string
function basePath(c: Context, index?: number): string

Build docs developers (and LLMs) love