0
0
NextjsHow-ToBeginner · 4 min read

How to Use Zod with Next.js for Validation

Use zod in Next.js by defining schemas to validate data, then parse inputs with schema.parse() or schema.safeParse(). This works well in API routes or form handling to ensure data correctness before processing.
📐

Syntax

Zod lets you create schemas to describe the shape and rules of your data. You define a schema with z.object() for objects, and use methods like string(), number(), and optional() to specify types and constraints. To validate data, use schema.parse(data) which throws on invalid data, or schema.safeParse(data) which returns a result object with success status.

typescript
import { z } from 'zod';

const schema = z.object({
  name: z.string(),
  age: z.number().int().positive(),
  email: z.string().email().optional()
});

// Validate data (throws error if invalid)
schema.parse({ name: 'Alice', age: 30 });

// Or safely parse data
const result = schema.safeParse({ name: 'Bob', age: 25 });
if (result.success) {
  // valid data in result.data
} else {
  // errors in result.error
}
💻

Example

This example shows how to use Zod in a Next.js API route to validate incoming JSON data before processing it. It returns a 400 error if validation fails, or a success message if data is valid.

typescript
import { NextApiRequest, NextApiResponse } from 'next';
import { z } from 'zod';

const userSchema = z.object({
  username: z.string().min(3),
  email: z.string().email(),
  age: z.number().int().positive().optional()
});

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') {
    res.status(405).json({ error: 'Method not allowed' });
    return;
  }

  const parseResult = userSchema.safeParse(req.body);

  if (!parseResult.success) {
    res.status(400).json({ error: parseResult.error.errors });
    return;
  }

  // Data is valid here
  const userData = parseResult.data;
  res.status(200).json({ message: 'User data is valid', user: userData });
}
Output
POST /api/user with body {"username":"joe","email":"joe@example.com"} Response: {"message":"User data is valid","user":{"username":"joe","email":"joe@example.com"}}
⚠️

Common Pitfalls

  • Not parsing the request body as JSON before validation can cause errors; Next.js API routes parse JSON automatically if Content-Type is application/json.
  • Using schema.parse() without try-catch will crash the server on invalid data; prefer safeParse() for safer error handling.
  • For optional fields, forgetting to mark them as optional() causes validation failures if missing.
  • Not validating query parameters or cookies if they are used as input can lead to unexpected bugs.
typescript
import { z } from 'zod';

const schema = z.object({
  name: z.string(),
  age: z.number().int()
});

// Wrong: parse throws error if invalid
try {
  schema.parse({ name: 'Ann' }); // Missing age
} catch (e) {
  console.error('Validation failed:', e.errors);
}

// Right: safeParse returns result object
const result = schema.safeParse({ name: 'Ann' });
if (!result.success) {
  console.log('Errors:', result.error.errors);
}
📊

Quick Reference

Here is a quick summary of common Zod methods used in Next.js:

MethodDescription
z.string()Validates a string value
z.number()Validates a number value
z.boolean()Validates a boolean value
z.object({...})Validates an object with specified shape
schema.parse(data)Validates data or throws error if invalid
schema.safeParse(data)Validates data and returns success status without throwing
z.optional(schema)Marks a schema as optional
z.array(schema)Validates an array of items matching schema
z.enum([...])Validates a value against a set of allowed strings

Key Takeaways

Use Zod schemas to define and validate data shapes clearly in Next.js.
Prefer safeParse() over parse() to handle validation errors gracefully.
Validate all external inputs like API request bodies to avoid bugs.
Mark optional fields explicitly with optional() to prevent validation failures.
Integrate Zod easily in Next.js API routes for robust data validation.