Skip to main content

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.

Overview

Routing in Hono maps HTTP requests to handler functions based on the request method and URL path. Hono provides a simple and intuitive API for defining routes with full type safety.

Defining Routes

Routes are defined using HTTP method helpers on the Hono application instance. Each method corresponds to a standard HTTP verb.

Basic Route Definition

import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => {
  return c.text('Hello Hono!')
})

app.post('/posts', (c) => {
  return c.json({ message: 'Post created' })
})

HTTP Method Handlers

Hono supports all standard HTTP methods through dedicated handler functions:
app.get('/users', (c) => c.text('GET /users'))
app.post('/users', (c) => c.text('POST /users'))
app.put('/users/:id', (c) => c.text('PUT /users/:id'))
app.delete('/users/:id', (c) => c.text('DELETE /users/:id'))
app.patch('/users/:id', (c) => c.text('PATCH /users/:id'))
app.options('/users', (c) => c.text('OPTIONS /users'))

Available Methods

From src/hono-base.ts:104-110:
get!: HandlerInterface<E, 'get', S, BasePath, CurrentPath>
post!: HandlerInterface<E, 'post', S, BasePath, CurrentPath>
put!: HandlerInterface<E, 'put', S, BasePath, CurrentPath>
delete!: HandlerInterface<E, 'delete', S, BasePath, CurrentPath>
options!: HandlerInterface<E, 'options', S, BasePath, CurrentPath>
patch!: HandlerInterface<E, 'patch', S, BasePath, CurrentPath>
all!: HandlerInterface<E, 'all', S, BasePath, CurrentPath>

The all Method

The all method matches any HTTP method:
app.all('/api/*', (c) => {
  return c.text('Matches all methods')
})

Path Patterns

Hono supports various path patterns for flexible route matching.

Static Paths

Exact path matching:
app.get('/about', (c) => c.text('About page'))
app.get('/contact', (c) => c.text('Contact page'))

Path Parameters

Capture dynamic segments using :param syntax:
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ userId: id })
})

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

Wildcard Paths

Match multiple path segments:
app.get('/files/*', (c) => {
  return c.text('Matches /files/any/path/here')
})

The on Method

For custom methods or matching multiple methods, use the on method:
// Single method
app.on('CUSTOM', '/webhook', (c) => {
  return c.text('Custom method handler')
})

// Multiple methods
app.on(['GET', 'POST'], '/dual', (c) => {
  return c.text(`Handled ${c.req.method}`)
})

// Multiple paths
app.on('GET', ['/path1', '/path2'], (c) => {
  return c.text('Multiple paths')
})
From src/hono-base.ts:144-154:
this.on = (method: string | string[], path: string | string[], ...handlers: H[]) => {
  for (const p of [path].flat()) {
    this.#path = p
    for (const m of [method].flat()) {
      handlers.map((handler) => {
        this.#addRoute(m.toUpperCase(), this.#path, handler)
      })
    }
  }
  return this as any
}

Route Grouping

Group routes with a common base path using route:
const api = new Hono()
api.get('/users', (c) => c.json({ users: [] }))
api.get('/posts', (c) => c.json({ posts: [] }))

const app = new Hono()
app.route('/api', api)
// Now accessible at /api/users and /api/posts
From src/hono-base.ts:208-232:
route<
  SubPath extends string,
  SubEnv extends Env,
  SubSchema extends Schema,
  SubBasePath extends string,
  SubCurrentPath extends string,
>(
  path: SubPath,
  app: Hono<SubEnv, SubSchema, SubBasePath, SubCurrentPath>
): Hono<E, MergeSchemaPath<SubSchema, MergePath<BasePath, SubPath>> | S, BasePath, CurrentPath>

Base Paths

Define a base path for all routes in an instance:
const api = new Hono().basePath('/api/v1')

api.get('/users', (c) => c.text('GET /api/v1/users'))
api.get('/posts', (c) => c.text('GET /api/v1/posts'))
From src/hono-base.ts:247-253:
basePath<SubPath extends string>(
  path: SubPath
): Hono<E, S, MergePath<BasePath, SubPath>, MergePath<BasePath, SubPath>> {
  const subApp = this.#clone()
  subApp._basePath = mergePath(this._basePath, path)
  return subApp
}

Route Matching

Routes are matched in the order they are defined. The first matching route handles the request.

Strict Mode

By default, Hono uses strict mode which distinguishes /path from /path/:
const app = new Hono({ strict: true }) // default

app.get('/users', handler) // Matches /users only
app.get('/posts/', handler) // Matches /posts/ only
Disable strict mode to treat both the same:
const app = new Hono({ strict: false })

app.get('/users', handler) // Matches both /users and /users/
From src/hono-base.ts:46-87:
type HonoOptions<E extends Env> = {
  /**
   * `strict` option specifies whether to distinguish whether the last path is a directory or not.
   *
   * @default true
   */
  strict?: boolean
  /**
   * `router` option specifies which router to use.
   */
  router?: Router<[H, RouterRoute]>
  /**
   * `getPath` can handle the host header value.
   */
  getPath?: GetPath<E>
}

Chaining Routes

Multiple handlers can be chained on the same path:
app
  .get('/users', (c) => c.json({ message: 'Getting users' }))
  .post('/users', (c) => c.json({ message: 'Creating user' }))
  .put('/users/:id', (c) => c.json({ message: 'Updating user' }))
From src/hono-base.ts:127-141, routes return the app instance for chaining:
allMethods.forEach((method) => {
  this[method] = (args1: string | H, ...args: H[]) => {
    if (typeof args1 === 'string') {
      this.#path = args1
    } else {
      this.#addRoute(method, this.#path, args1)
    }
    args.forEach((handler) => {
      this.#addRoute(method, this.#path, handler)
    })
    return this as any
  }
})

Route Information

Access registered routes through the routes property:
const app = new Hono()
app.get('/users', handler)
app.post('/posts', handler)

console.log(app.routes)
// Returns RouterRoute[] with route metadata
From src/types.ts:57-62:
interface RouterRoute {
  basePath: string
  path: string
  method: string
  handler: H
}

Best Practices

  • Define specific routes before wildcard routes
  • Use route grouping for better organization
  • Leverage TypeScript for path parameter type safety
  • Use basePath for API versioning
Wildcard routes (*) should be defined last, as they will match any path that hasn’t been matched by previous routes.

Build docs developers (and LLMs) love