
How to Use Zod in TypeScript Projects for Validation and Safety
Zod is one of the best libraries out there for validating data in TypeScript projects. It’s fast, type-safe, and works beautifully for both backend APIs and frontend forms.
In this guide, we’ll walk through how to:
- Use Zod to validate incoming API requests in Node.js
- Use Zod with React Hook Form for frontend form validation
Step 1: Installing Zod
First things first — install Zod in your project:
npm install zod
Click to Copy
If you're using it with React Hook Form:
npm install react-hook-form @hookform/resolvers
Click to Copy
Step 2: What is Zod and Why Use It?
Zod is a TypeScript-first schema validation library. That means you write your validation rules using Zod, and it automatically gives you fully typed objects.
You can use it to:
- Safely validate user input
- Share the same schema between backend and frontend
- Avoid writing repetitive type definitions and manual checks
Step 3: Validating API Input in Node.js
Let’s say you’re building a user registration API. You want to make sure that the data sent to the server is actually valid — no missing fields, no bad email formats, etc.
Create a Schema
// schemas/user.schema.ts import { z } from "zod"; export const userSchema = z.object({ name: z.string().min(2, "Name must be at least 2 characters"), email: z.string().email("Please enter a valid email"), password: z.string().min(6, "Password must be at least 6 characters"), });
Click to Copy
Use the Schema in an API Route
// routes/user.ts import express from "express"; import { userSchema } from "../schemas/user.schema"; const router = express.Router(); router.post("/register", (req, res) => { const result = userSchema.safeParse(req.body); if (!result.success) { return res.status(400).json({ errors: result.error.flatten().fieldErrors, }); } const user = result.data; res.status(200).json({ message: "User registered", user }); });
Click to Copy
✅ 'safeParse()' lets you check if the input is valid and safely access the typed data.
Step 4: Form Validation in React with React Hook Form + Zod
Zod works perfectly with React Hook Form. You can reuse the same schema on the frontend that you used on the backend.
Set Up the Schema
// schemas/user.schema.ts import { z } from "zod"; export const userSchema = z.object({ name: z.string().min(2, "Name must be at least 2 characters"), email: z.string().email("Please enter a valid email"), password: z.string().min(6, "Password too short"), }); export type UserSchemaType = z.infer<typeof userSchema>;
Click to Copy
Use It in a Form
// components/RegisterForm.tsx "use client"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { userSchema, UserSchemaType } from "../schemas/user.schema"; export default function RegisterForm() { const { register, handleSubmit, formState: { errors }, } = useForm<UserSchemaType>({ resolver: zodResolver(userSchema), }); const onSubmit = (data: UserSchemaType) => { console.log("Submitted data:", data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <div> <input type="text" placeholder="Name" {...register("name")} /> {errors.name && <p>{errors.name.message}</p>} </div> <div> <input type="email" placeholder="Email" {...register("email")} /> {errors.email && <p>{errors.email.message}</p>} </div> <div> <input type="password" placeholder="Password" {...register("password")} /> {errors.password && <p>{errors.password.message}</p>} </div> <button type="submit">Register</button> </form> ); }
Click to Copy
This form is fully typed and will only submit valid data — and you didn’t have to write any custom validation logic.
Step 5: Some Cool Things Zod Can Do
Transform values
Need to convert a string to a number on the fly?
const schema = z.object({ age: z.string().transform((val) => Number(val)), });
Click to Copy
Nest schemas
You can compose schemas easily:
const addressSchema = z.object({ city: z.string(), zip: z.string(), }); const userSchema = z.object({ name: z.string(), address: addressSchema, });
Click to Copy
Custom error messages
Zod lets you add readable, user-friendly errors:
z.string().min(1, { message: "This field is required" });
Click to Copy
Final Thoughts
Zod is an amazing tool for modern TypeScript development. Whether you're building APIs or forms, it helps you:
- Avoid bugs from invalid data
- Write cleaner code with less boilerplate
- Share logic across your stack
If you're using TypeScript, Zod should be part of your toolkit. Give it a try in your next project — you’ll never look back.