Blog
Wild & Free Tools

Next.js + Zod Form Validation: Schema Setup Guide

Last updated: April 2026 7 min read

Table of Contents

  1. Why Zod Is the Standard for Next.js Validation
  2. Step 1: Create the Zod Schema
  3. Step 2: Connect to React Hook Form
  4. Step 3: Validate in Server Actions
  5. Frequently Asked Questions

Next.js form validation with Zod works by defining a z.object() schema for your form fields, connecting it to React Hook Form via zodResolver, and reusing the same schema in Server Actions for server-side validation. One schema covers both client and server.

This guide shows the full setup: schema creation, React Hook Form integration, Server Actions validation, and how to generate schemas quickly from real data.

Why Zod Is the Standard for Next.js Validation

Zod has become the default validation library for Next.js projects for several reasons:

Step 1: Create the Zod Schema

If you have a sample form submission or API payload, paste it into the JSON to Zod converter to generate a base schema, then add form-specific constraints.

A typical signup form schema:

// lib/schemas/signup.ts
import { z } from 'zod';

export const SignupSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
  confirmPassword: z.string()
}).refine(data => data.password === data.confirmPassword, {
  message: 'Passwords do not match',
  path: ['confirmPassword']
});

export type SignupFormData = z.infer<typeof SignupSchema>;
Sell Custom Apparel — We Handle Printing & Free Shipping

Step 2: Connect to React Hook Form

Install the resolver:

npm install react-hook-form @hookform/resolvers zod
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { SignupSchema, SignupFormData } from '@/lib/schemas/signup';

export function SignupForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<SignupFormData>({
    resolver: zodResolver(SignupSchema)
  });

  const onSubmit = (data: SignupFormData) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} />
      {errors.email && <p>{errors.email.message}</p>}
    </form>
  );
}

Step 3: Validate in Server Actions

Reuse the same schema in a Server Action — never trust client-side validation alone:

// app/actions/signup.ts
'use server';
import { SignupSchema } from '@/lib/schemas/signup';

export async function signupAction(formData: FormData) {
  const raw = {
    name: formData.get('name'),
    email: formData.get('email'),
    password: formData.get('password'),
    confirmPassword: formData.get('confirmPassword')
  };

  const result = SignupSchema.safeParse(raw);

  if (!result.success) {
    return { errors: result.error.flatten().fieldErrors };
  }

  const { name, email, password } = result.data;
  // proceed with signup
}

error.flatten().fieldErrors returns an object with field-level error arrays — easy to display next to each input.

Try It Free — No Signup Required

Runs 100% in your browser. No data is collected, stored, or sent anywhere.

Open Free JSON to Zod Converter

Frequently Asked Questions

How do I add Zod validation to a Next.js form?

Install react-hook-form and @hookform/resolvers. Create a z.object() schema, then pass zodResolver(YourSchema) to useForm. Errors appear in formState.errors with field paths.

Can I use the same Zod schema on both client and server in Next.js?

Yes. Define the schema in a shared lib/schemas file and import it in both the React Hook Form component (client) and the Server Action (server). One schema, zero duplication.

How do I validate Server Action inputs with Zod?

Call YourSchema.safeParse(rawFormData) inside the server action. Check result.success. If false, return result.error.flatten().fieldErrors to the client for display.

How do I generate a Zod schema from a JSON sample for my Next.js form?

Paste a sample form submission JSON into the free converter at /developer-tools/json-to-zod/. It outputs the base z.object() schema. Add .min(), .email(), .refine() and other constraints on top.

Launch Your Own Clothing Brand — No Inventory, No Risk