> ## 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.

# Validation

> Learn how to validate request data in Hono using the built-in validator and third-party libraries.

## Overview

Hono provides a powerful and flexible validation system that allows you to validate incoming request data from various sources including JSON bodies, form data, query parameters, headers, and cookies.

## Basic Validation

The `validator` middleware extracts data from different parts of the request and validates it using a custom validation function.

### Validation Targets

You can validate data from these sources:

* `json` - JSON request body
* `form` - Form data (multipart or URL-encoded)
* `query` - Query parameters
* `param` - Path parameters
* `header` - Request headers
* `cookie` - Cookies

### Basic Example

```typescript theme={null}
import { Hono } from 'hono'
import { validator } from 'hono/validator'

const app = new Hono()

app.post(
  '/posts',
  validator('json', (value, c) => {
    const parsed = value as { title: string; body: string }
    if (!parsed.title || typeof parsed.title !== 'string') {
      return c.text('Invalid title', 400)
    }
    if (!parsed.body || typeof parsed.body !== 'string') {
      return c.text('Invalid body', 400)
    }
    return parsed
  }),
  (c) => {
    const { title, body } = c.req.valid('json')
    return c.json({ message: 'Created', title, body })
  }
)
```

## Query Parameter Validation

Validate URL query parameters:

```typescript theme={null}
app.get(
  '/search',
  validator('query', (value, c) => {
    const query = value as { q: string; limit?: string }
    if (!query.q) {
      return c.text('Missing search query', 400)
    }
    return {
      q: query.q,
      limit: query.limit ? parseInt(query.limit) : 10,
    }
  }),
  (c) => {
    const { q, limit } = c.req.valid('query')
    return c.json({ results: [], query: q, limit })
  }
)
```

## Form Data Validation

Validate form data submissions:

```typescript theme={null}
app.post(
  '/upload',
  validator('form', (value, c) => {
    const form = value as { name: string; file: File }
    if (!form.name) {
      return c.text('Name is required', 400)
    }
    if (!form.file || !(form.file instanceof File)) {
      return c.text('Valid file is required', 400)
    }
    return form
  }),
  (c) => {
    const { name, file } = c.req.valid('form')
    return c.json({ message: 'Uploaded', name, size: file.size })
  }
)
```

## Multiple Validators

Chain multiple validators to validate different parts of the request:

```typescript theme={null}
app.post(
  '/posts/:id/comments',
  validator('param', (value, c) => {
    const id = parseInt(value.id as string)
    if (isNaN(id)) {
      return c.text('Invalid ID', 400)
    }
    return { id }
  }),
  validator('json', (value, c) => {
    const data = value as { comment: string }
    if (!data.comment || data.comment.length < 1) {
      return c.text('Comment is required', 400)
    }
    return data
  }),
  (c) => {
    const { id } = c.req.valid('param')
    const { comment } = c.req.valid('json')
    return c.json({ postId: id, comment, created: true })
  }
)
```

## Using Zod

For more complex validation, use Zod with Hono's validator:

```typescript theme={null}
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'

const schema = z.object({
  title: z.string().min(1).max(100),
  body: z.string().min(1),
  tags: z.array(z.string()).optional(),
  published: z.boolean().default(false),
})

app.post('/posts', zValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  // data is fully typed!
  return c.json({ message: 'Created', data })
})
```

## Custom Error Messages

Return custom error responses:

```typescript theme={null}
import { HTTPException } from 'hono/http-exception'

app.post(
  '/api/users',
  validator('json', (value, c) => {
    const data = value as { email: string; password: string }
    
    if (!data.email || !data.email.includes('@')) {
      throw new HTTPException(400, { 
        message: 'Invalid email address' 
      })
    }
    
    if (!data.password || data.password.length < 8) {
      throw new HTTPException(400, { 
        message: 'Password must be at least 8 characters' 
      })
    }
    
    return data
  }),
  (c) => {
    const user = c.req.valid('json')
    return c.json({ message: 'User created', email: user.email })
  }
)
```

## Validation Utilities

The validator automatically handles:

* Content-Type detection for JSON (`application/json`)
* Form data parsing (both `multipart/form-data` and `application/x-www-form-urlencoded`)
* Array handling in form data (fields ending with `[]`)
* Type safety with TypeScript

## Best Practices

<AccordionGroup>
  <Accordion title="Always validate user input">
    Never trust data from clients. Always validate and sanitize input before processing.
  </Accordion>

  <Accordion title="Use TypeScript for type safety">
    Leverage TypeScript's type system along with validation to catch errors early.
  </Accordion>

  <Accordion title="Return meaningful error messages">
    Provide clear, actionable error messages to help API consumers fix issues.
  </Accordion>

  <Accordion title="Consider using validation libraries">
    For complex validation logic, use libraries like Zod, Valibot, or TypeBox with Hono validators.
  </Accordion>
</AccordionGroup>

## Related

* [Error Handling](/guides/error-handling) - Learn how to handle validation errors
* [TypeScript](/guides/typescript) - Type-safe validation with TypeScript
* [Third-party Validators](https://hono.dev/docs/helpers/adapter#validators) - Integration with popular validation libraries
