Routing
Hono provides a flexible and powerful routing system that supports various path patterns, parameters, and multiple router implementations.
Route Patterns
Basic Routes
Define routes using simple string paths.
app . get ( '/' , ( c ) => c . text ( 'Home' ))
app . get ( '/about' , ( c ) => c . text ( 'About' ))
app . get ( '/contact' , ( c ) => c . text ( 'Contact' ))
Path Parameters
Capture dynamic segments in the URL path.
// Single parameter
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 })
})
// Optional parameters
app . get ( '/users/:id?' , ( c ) => {
const id = c . req . param ( 'id' ) // string | undefined
return c . json ({ id })
})
Wildcard Routes
Match multiple path segments.
// Match any path
app . get ( '*' , ( c ) => c . text ( 'Catch all' ))
// Match paths starting with /api/
app . get ( '/api/*' , ( c ) => c . text ( 'API route' ))
// Match with prefix
app . get ( '/files/*' , ( c ) => {
const path = c . req . path // e.g., '/files/documents/report.pdf'
return c . text ( `File: ${ path } ` )
})
Regular Expressions
Use regex patterns in routes.
// Match numeric IDs only
app . get ( '/users/:id{[0-9]+}' , ( c ) => {
const id = c . req . param ( 'id' ) // guaranteed to be numeric string
return c . json ({ userId: id })
})
// Match specific patterns
app . get ( '/posts/:slug{[a-z-]+}' , ( c ) => {
const slug = c . req . param ( 'slug' )
return c . json ({ slug })
})
Multiple Paths
Register the same handler for multiple paths using app.on().
app . on ( 'GET' , [ '/v1/users' , '/v2/users' ], ( c ) => {
return c . json ({ users: [] })
})
Route Methods
HTTP Methods
Hono supports all standard HTTP methods.
app . get ( '/resource' , ( c ) => c . text ( 'GET' ))
app . post ( '/resource' , ( c ) => c . text ( 'POST' ))
app . put ( '/resource' , ( c ) => c . text ( 'PUT' ))
app . patch ( '/resource' , ( c ) => c . text ( 'PATCH' ))
app . delete ( '/resource' , ( c ) => c . text ( 'DELETE' ))
app . options ( '/resource' , ( c ) => c . text ( 'OPTIONS' ))
All Methods
Match all HTTP methods for a route.
app . all ( '/api/status' , ( c ) => {
return c . json ({ status: 'ok' , method: c . req . method })
})
Custom Methods
Handle custom HTTP methods.
app . on ( 'PURGE' , '/cache' , ( c ) => {
return c . text ( 'Cache purged' )
})
app . on ([ 'LINK' , 'UNLINK' ], '/resource' , ( c ) => {
return c . text ( `Method: ${ c . req . method } ` )
})
Route Grouping
Using basePath
Create a Hono instance with a base path prefix.
const api = new Hono (). basePath ( '/api/v1' )
api . get ( '/users' , ( c ) => c . json ({ users: [] })) // GET /api/v1/users
api . get ( '/posts' , ( c ) => c . json ({ posts: [] })) // GET /api/v1/posts
api . get ( '/comments' , ( c ) => c . json ({ comments: [] })) // GET /api/v1/comments
const app = new Hono ()
app . route ( '/' , api )
Using route
Mount sub-applications to group related routes.
const app = new Hono ()
// User routes
const users = new Hono ()
users . get ( '/' , ( c ) => c . json ({ users: [] }))
users . get ( '/:id' , ( c ) => c . json ({ user: {} }))
users . post ( '/' , ( c ) => c . json ({ created: true }))
// Post routes
const posts = new Hono ()
posts . get ( '/' , ( c ) => c . json ({ posts: [] }))
posts . get ( '/:id' , ( c ) => c . json ({ post: {} }))
posts . post ( '/' , ( c ) => c . json ({ created: true }))
// Mount sub-apps
app . route ( '/users' , users )
app . route ( '/posts' , posts )
// Routes available:
// GET /users
// GET /users/:id
// POST /users
// GET /posts
// GET /posts/:id
// POST /posts
Router Configuration
Router Options
Configure the router when creating a Hono instance.
import { Hono } from 'hono'
import { RegExpRouter } from 'hono/router/reg-exp-router'
import { TrieRouter } from 'hono/router/trie-router'
import { SmartRouter } from 'hono/router/smart-router'
// Use a specific router
const app = new Hono ({ router: new RegExpRouter () })
// Use SmartRouter with custom routers
const app2 = new Hono ({
router: new SmartRouter ({
routers: [ new RegExpRouter (), new TrieRouter ()]
})
})
Available Routers
Hono includes several router implementations:
RegExpRouter Fast regex-based router. Good for most use cases. Default in SmartRouter.
TrieRouter Trie-based router. Excellent for apps with many routes. Default in SmartRouter.
SmartRouter Combines multiple routers for optimal performance. Default router in Hono.
LinearRouter Simple linear search router. Good for simple apps with few routes.
PatternRouter URLPattern-based router. Uses the web standard URLPattern API.
See the Router API Reference for detailed information about each router.
Strict Mode
Control whether trailing slashes matter in route matching.
// Strict mode enabled (default)
const app = new Hono ({ strict: true })
app . get ( '/about' , handler ) // Matches /about only
app . get ( '/contact/' , handler ) // Matches /contact/ only
// Strict mode disabled
const app2 = new Hono ({ strict: false })
app2 . get ( '/about' , handler ) // Matches both /about and /about/
Custom Path Function
Customize how paths are extracted from requests.
const app = new Hono ({
getPath : ( req ) => {
// Include host header in routing
const host = req . headers . get ( 'host' )
const path = new URL ( req . url ). pathname
return `/ ${ host }${ path } `
}
})
// Route based on host and path
app . get ( '/api.example.com/users' , handler1 )
app . get ( '/admin.example.com/users' , handler2 )
Route Priority
Matching Order
Routes are matched in the order they are registered.
app . get ( '/users/me' , ( c ) => c . text ( 'Current user' ))
app . get ( '/users/:id' , ( c ) => c . text ( 'User by ID' ))
// GET /users/me → matches first route
// GET /users/123 → matches second route
The order of route registration matters! More specific routes should be registered before generic ones.
Wildcard Priority
Wildcard routes have the lowest priority.
app . get ( '/api/users' , ( c ) => c . text ( 'Users' ))
app . get ( '/api/*' , ( c ) => c . text ( 'API catch-all' ))
app . get ( '*' , ( c ) => c . text ( 'Global catch-all' ))
// GET /api/users → first route
// GET /api/posts → second route
// GET /other → third route
RouterRoute Interface
Each route is represented by a RouterRoute object.
interface RouterRoute {
basePath : string
path : string
method : string
handler : H
}
Accessing Routes
Get all registered routes from the app.
const app = new Hono ()
app . get ( '/users' , handler )
app . post ( '/users' , handler )
console . log ( app . routes )
// [
// { basePath: '/', path: '/users', method: 'GET', handler: [Function] },
// { basePath: '/', path: '/users', method: 'POST', handler: [Function] }
// ]
Route Matching
Match Results
The router returns match results containing handlers and parameters.
type Result < T > =
| [[ T , ParamIndexMap ][], ParamStash ]
| [[ T , Params ][]]
Parameters are extracted and decoded automatically.
app . get ( '/users/:id' , ( c ) => {
// URL: /users/john%20doe
const id = c . req . param ( 'id' ) // 'john doe' (decoded)
return c . json ({ id })
})
Best Practices
Use specific routes before wildcards
Register more specific routes before generic wildcard routes to ensure correct matching. app . get ( '/users/me' , handler1 ) // Specific
app . get ( '/users/:id' , handler2 ) // Less specific
app . get ( '/users/*' , handler3 ) // Least specific
Use regex patterns for validation
Add regex patterns to route parameters to validate input at the routing level. app . get ( '/users/:id{[0-9]+}' , handler ) // Only numeric IDs
For most applications, the default SmartRouter is optimal. Consider specific routers for specialized needs:
LinearRouter for very simple apps
RegExpRouter for regex-heavy patterns
TrieRouter for apps with many routes
Type Safety
Typed Routes
Use TypeScript for type-safe routing.
import { Hono } from 'hono'
type Env = {
Variables : {
user : { id : string ; name : string }
}
}
const app = new Hono < Env >()
app . get ( '/users/:id' , ( c ) => {
const id = c . req . param ( 'id' ) // Type-safe string
const user = c . get ( 'user' ) // Type-safe user object
return c . json ( user )
})
Schema Definition
Define API schemas for type-safe client generation.
import { Hono } from 'hono'
import type { Schema } from 'hono'
type AppSchema = {
'/api/users' : {
GET : {
response : { users : User [] }
}
}
}
const app = new Hono <{}, AppSchema >()