Last Updated: 3/11/2026
Validation
Hono provides a lightweight validator that becomes powerful when combined with third-party validation libraries like Zod, Valibot, or ArkType.
Manual Validation
Use the validator function for basic validation:
import { validator } from 'hono/validator'
app.post(
'/posts',
validator('form', (value, c) => {
const body = value['body']
if (!body || typeof body !== 'string') {
return c.text('Invalid!', 400)
}
return { body }
}),
(c) => {
const { body } = c.req.valid('form')
return c.json({ message: 'Created!', body }, 201)
}
)Validation Targets
Validate different parts of the request:
json- Request body (JSON)form- Form dataquery- URL query parametersparam- Path parametersheader- Request headerscookie- Cookies
Important: For json and form, the request must have the matching Content-Type header.
Zod Validator
Use Zod for schema validation:
npm install @hono/zod-validator zodimport { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const schema = z.object({
title: z.string().min(1),
body: z.string().min(10),
})
app.post(
'/posts',
zValidator('json', schema),
(c) => {
const { title, body } = c.req.valid('json')
return c.json({ message: 'Created!', title, body }, 201)
}
)Standard Schema Validator
The Standard Schema validator works with multiple validation libraries:
npm install @hono/standard-validatorWith Zod
import { sValidator } from '@hono/standard-validator'
import * as z from 'zod'
const schema = z.object({
name: z.string(),
age: z.number(),
})
app.post('/author', sValidator('json', schema), (c) => {
const data = c.req.valid('json')
return c.json({
success: true,
message: `${data.name} is ${data.age}`,
})
})With Valibot
npm install valibotimport { sValidator } from '@hono/standard-validator'
import * as v from 'valibot'
const schema = v.object({
name: v.string(),
age: v.number(),
})
app.post('/author', sValidator('json', schema), (c) => {
const data = c.req.valid('json')
return c.json({ success: true, message: `${data.name} is ${data.age}` })
})With ArkType
npm install arktypeimport { sValidator } from '@hono/standard-validator'
import { type } from 'arktype'
const schema = type({
name: 'string',
age: 'number',
})
app.post('/author', sValidator('json', schema), (c) => {
const data = c.req.valid('json')
return c.json({ success: true, message: `${data.name} is ${data.age}` })
})Multiple Validators
Validate different parts of a request:
app.post(
'/posts/:id',
zValidator('param', z.object({ id: z.string() })),
zValidator('query', z.object({ page: z.string().optional() })),
zValidator('json', z.object({ title: z.string(), body: z.string() })),
(c) => {
const { id } = c.req.valid('param')
const { page } = c.req.valid('query')
const { title, body } = c.req.valid('json')
return c.json({ id, page, title, body })
}
)Header Validation
When validating headers, use lowercase keys:
app.post(
'/api',
validator('header', (value, c) => {
// Use lowercase 'idempotency-key'
const idempotencyKey = value['idempotency-key']
if (!idempotencyKey) {
return c.json({ error: 'Idempotency-Key required' }, 400)
}
return { idempotencyKey }
}),
(c) => {
const { idempotencyKey } = c.req.valid('header')
return c.json({ received: idempotencyKey })
}
)Error Handling
Handle validation errors:
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
app.post(
'/posts',
zValidator(
'json',
z.object({
title: z.string(),
}),
(result, c) => {
if (!result.success) {
return c.json({ error: result.error.errors }, 400)
}
}
),
(c) => {
const data = c.req.valid('json')
return c.json({ success: true, data })
}
)Next Steps
Learn about type-safe client-server communication with RPC.