Skip to Content
docsapiRequest

Last Updated: 3/9/2026


HonoRequest

The HonoRequest is an object that can be taken from c.req which wraps a Request  object.

param()

Get the values of path parameters.

import { Hono } from 'hono' const app = new Hono() // ---cut--- // Captured params app.get('/entry/:id', async (c) => { const id = c.req.param('id') // ^? // ... }) // Get all params at once app.get('/entry/:id/comment/:commentId', async (c) => { const { id, commentId } = c.req.param() // ^? })

query()

Get querystring parameters.

import { Hono } from 'hono' const app = new Hono() // ---cut--- // Query params app.get('/search', async (c) => { const query = c.req.query('q') // ^? }) // Get all params at once app.get('/search', async (c) => { const { q, limit, offset } = c.req.query() // ^? })

queries()

Get multiple querystring parameter values, e.g. /search?tags=A&tags=B

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/search', async (c) => { // tags will be string[] const tags = c.req.queries('tags') // ^? // ... })

Get the request header value.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/', (c) => { const userAgent = c.req.header('User-Agent') // ^? return c.text(`Your user agent is ${userAgent}`) })

::: warning When c.req.header() is called with no arguments, all keys in the returned record are lowercase.

If you want to get the value of a header with an uppercase name, use c.req.header(“X-Foo”).

// ❌ Will not work const headerRecord = c.req.header() const foo = headerRecord['X-Foo'] // ✅ Will work const foo = c.req.header('X-Foo')

:::

parseBody()

Parse Request body of type multipart/form-data or application/x-www-form-urlencoded

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.parseBody() // ... })

parseBody() supports the following behaviors.

Single file

import { Context } from 'hono' declare const c: Context // ---cut--- const body = await c.req.parseBody() const data = body['foo'] // ^?

body['foo'] is (string | File).

If multiple files are uploaded, the last one will be used.

Multiple files

import { Context } from 'hono' declare const c: Context // ---cut--- const body = await c.req.parseBody() body['foo[]']

body['foo[]'] is always (string | File)[].

[] postfix is required.

Multiple files or fields with same name

If you have a input field that allows multiple <input type="file" multiple /> or multiple checkboxes with the same name <input type="checkbox" name="favorites" value="Hono"/>.

import { Context } from 'hono' declare const c: Context // ---cut--- const body = await c.req.parseBody({ all: true }) body['foo']

all option is disabled by default.

  • If body['foo'] is multiple files, it will be parsed to (string | File)[].
  • If body['foo'] is single file, it will be parsed to (string | File).

Dot notation

If you set the dot option true, the return value is structured based on the dot notation.

Imagine receiving the following data:

const data = new FormData() data.append('obj.key1', 'value1') data.append('obj.key2', 'value2')

You can get the structured value by setting the dot option true:

import { Context } from 'hono' declare const c: Context // ---cut--- const body = await c.req.parseBody({ dot: true }) // body is `{ obj: { key1: 'value1', key2: 'value2' } }`

json()

Parses the request body of type application/json

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.json() // ... })

text()

Parses the request body of type text/plain

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.text() // ... })

arrayBuffer()

Parses the request body as an ArrayBuffer

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.arrayBuffer() // ... })

blob()

Parses the request body as a Blob.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.blob() // ... })

formData()

Parses the request body as a FormData.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.post('/entry', async (c) => { const body = await c.req.formData() // ... })

valid()

Get the validated data.

app.post('/posts', async (c) => { const { title, body } = c.req.valid('form') // ... })

Available targets are below.

  • form
  • json
  • query
  • header
  • cookie
  • param

See the Validation section for usage examples.

routePath

::: warning Deprecated in v4.8.0: This property is deprecated. Use routePath() from Route Helper instead. :::

You can retrieve the registered path within the handler like this:

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/posts/:id', (c) => { return c.json({ path: c.req.routePath }) })

If you access /posts/123, it will return /posts/:id:

{ "path": "/posts/:id" }

matchedRoutes

::: warning Deprecated in v4.8.0: This property is deprecated. Use matchedRoutes() from Route Helper instead. :::

It returns matched routes within the handler, which is useful for debugging.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.use(async function logger(c, next) { await next() c.req.matchedRoutes.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' : '' ) }) })

path

The request pathname.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/about/me', async (c) => { const pathname = c.req.path // `/about/me` // ... })

url

The request url strings.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/about/me', async (c) => { const url = c.req.url // `http://localhost:8787/about/me` // ... })

method

The method name of the request.

import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/about/me', async (c) => { const method = c.req.method // `GET` // ... })

raw

The raw Request object.

// For Cloudflare Workers app.post('/', async (c) => { const metadata = c.req.raw.cf?.hostMetadata? // ... })

cloneRawRequest()

Clones the raw Request object from a HonoRequest. Works even after the request body has been consumed by validators or HonoRequest methods.

import { Hono } from 'hono' const app = new Hono() import { cloneRawRequest } from 'hono/request' import { validator } from 'hono/validator' app.post( '/forward', validator('json', (data) => data), async (c) => { // Clone after validation const clonedReq = await cloneRawRequest(c.req) // Does not throw the error await clonedReq.json() // ... } )