Zod is a TypeScript-first schema declaration and validation library designed to ensure both compile-time type safety and runtime data validation.
If you’re working with modern JavaScript or TypeScript applications, Zod helps you validate inputs, API responses, and complex data structures with ease — all while keeping your codebase clean, type-safe, and developer-friendly.
Zod is available on npm and maintained actively on GitHub. It’s a lightweight and powerful alternative to larger libraries like Joi or Yup — offering a much tighter integration with the TypeScript type system.
So, what problem does Zod solve? It eliminates the disconnect between your TypeScript types and actual runtime validation. With Zod Validation, you write your validation logic once, and TypeScript automatically infers the types — no duplication required.
Whether you’re validating forms, parsing JSON, or building APIs, Zod makes it effortless. Curious how it works? Here’s a quick example of Zod validation in action:
import { z } from 'zod';
const userSchema = z.object({
name: z.string(),
email: z.string().email(),
age: z.number().int().positive(),
});
userSchema.parse({
name: "Sharukhan Patan",
email: "sharukhanpatan@example.com",
age: 25,
});
Want to learn more? Explore the official Zod documentation or dive into practical use cases in our full guide.
For size-sensitive applications, check out Zod Mini, a lightweight variant designed for tree-shaking.
Primitives & Basic Types in Zod
Zod supports all major JavaScript primitives:
- Primitives:
z.string()
,z.number()
,z.boolean()
,z.bigint()
,z.date()
- Booleans: Use
z.boolean()
for strict boolean validation. - Numbers & Integers: Validate numbers with
z.number()
and ensure integers using.int()
. - BigInts: For large numbers exceeding 64-bit precision.
- Dates: Use
z.date()
forDate
object validation.
Working with Strings in Zod
Strings are a fundamental data type in Zod, and proper validation is essential for form inputs, API data, and database entries. You can handle everything from basic validation with z.string()
to advanced techniques like length constraints, coercion, transformations, literals, and format-specific validations.
Enhances string validation with format checks:
- Strings:
z.string()
with methods like.min()
,.max()
,.regex()
- String Formats:
z.email()
- This method is used to validate email inputs in Zod. It ensures the value matches a valid email format, making it the go-to choice for Zod email validation.
- The Zod email check with
z.string().email()
is deprecated.
z.uuid()
– UUIDsz.url().optional()
- This method is used to validate strings as proper URLs. This is the recommended way to perform Zod URL validation and ensure your inputs follow valid URL format. For fields that aren’t required, you can use Zod URL Optional by chaining .optional(), which validates any provided URL while allowing missing values.
- Zod URL check with
z.string().url()
is deprecated.
z.string().ip()
– IP addressesz.iso.datetime()
- This method ensures the string is a valid ISO datetime (e.g.,
YYYY-MM-DDTHH:MM:SSZ
). It’s perfect for full Zod datetime validation. - The Zod datetime check with
z.string().datetime()
is deprecated.
- This method ensures the string is a valid ISO datetime (e.g.,
z.date()
- This method checks for ISO date strings (e.g.,
YYYY-MM-DD
). It’s ideal for ensuring consistent Zod date format validation. - The Zod date check with
z.string().date()
is deprecated.
- This method checks for ISO date strings (e.g.,
z.time()
- This method validates ISO time strings like
HH:MM:SS
. Use this for strict Zod time format checks. - The Zod time check with
z.string().time()
is deprecated.
- This method validates ISO time strings like
z.string().includes()
,startsWith()
,endsWith()
– string operations
For a complete deep dive into Zod string validation and operations, check out our string handling guide.
Working with Numbers in Zod
Numbers are one of the most essential data types in Zod, used across forms, APIs, and backend logic for everything from user ages to prices and IDs.
With Zod’s numeric schema, you can ensure values are valid numbers using z.number()
, apply precise range limits with min
, max
, lte
, and gte
, handle flexible input types through coercion, and even perform runtime transformations to adjust or sanitize values.
Whether you’re validating form inputs, API payloads, or database records, Zod provides a complete toolkit for safe and consistent numeric validation.
For a complete deep dive into Zod number validation and operations, check out our number handling guide.
Coerce in Zod
Zod’s coerce
feature simplifies schema validation by automatically converting input values into the expected data type. In modern web applications, form fields and API inputs often arrive as strings, even when they represent numbers, booleans, or dates. Without coercion, developers would need to manually transform every input before validating it, which is repetitive and error-prone.
With z.coerce
, values are automatically converted into numbers, strings, booleans, dates, or BigInts, ensuring consistent and predictable types across your application. Combined with custom error messages and validation methods like .min()
or .max()
, coercion makes Zod a powerful tool for handling real-world user inputs.
Coercion is one part of Zod’s powerful validation toolkit. To see it in action with examples, edge cases, and best practices, explore Zod Coerce in detail.
Literals in Zod
z.literal()
allows you to validate a single exact value—or multiple allowed values in Zod v4 — ensuring your data strictly matches predefined constants. It’s ideal for forms, API requests, or configuration objects where only specific values are permitted.
const role = z.literal("admin");
role.parse("admin"); // works
role.parse("user"); // throws error
Learn how to handle strings, numbers, booleans, arrays of literals, and edge cases for safer, predictable data. Complete Guide on Zod Literals
Enums in Zod
- Enums:
z.enum(['admin', 'user'])
for string enums.enum
– keyword alias for defining enum types.exclude()
,.extract()
– filter enum variants- Compare:
zod enum vs literal
Need advanced enum usage? Explore the full Zod Enum guide →
Objects & Object Utilities in Zod
Zod offers powerful utilities for defining and extending objects:
- Basic Object:
z.object({ name: z.string() })
- Strict vs Loose:
z.strictObject()
– disallow unknown keysz.looseObject()
– allow unknown keys
- Utilities:
.shape
(),.keyof()
,.extend()
,.pick()
,.omit()
,.partial()
,.required()
.catchall()
– allow extra properties
- Recursive objects: Create nested schemas using
z.lazy()
- Circularity errors: Solve by wrapping references with
z.lazy()
Arrays, Tuples & Unions in Zod
Working with collections and multiple type options:
- Arrays:
z.array(z.string())
- Tuples: Fixed-length, typed arrays
- Unions:
z.union([z.string(), z.number()])
- Discriminated Unions: For object shapes with a shared tag/key
- Intersections: Combine multiple schemas:
z.intersection(A, B)
Want to explore all the ways you can validate arrays in Zod?
Check out our complete guide on Zod arrays — packed with use cases, constraints, transformation techniques, and best practices.
Advanced Structures in Zod
Zod supports several advanced data structures beyond standard objects and arrays. Use z.record()
to validate object maps with consistent key-value types — perfect for dictionaries or dynamic objects.
Zod also offers native support for Map
and Set
via z.map()
and z.set()
, ensuring proper shape and content validation. For file uploads or browser blobs, z.instanceof(Blob)
can validate file-like objects.
You can also validate class instances using z.instanceof(Class)
. Note that z.promise()
is deprecated in Zod 4, as schema-based promise validation has been removed in favor of cleaner async validation patterns.
- Records: Object maps with uniform key-value types
- Maps & Sets: Validate native
Map
andSet
usingz.map()
andz.set()
- Files: Validate file-like objects (e.g.,
Blob
) - Promises: Schema for promise results using
z.promise()
[deprecated in zod 4] - Instanceof: Use
z.instanceof(Class)
for class validations
Refinements & Custom Validations in Zod
Zod offers refinement methods to add custom validation logic beyond built-in rules. Use .refine()
for simple post-validation checks, like confirming passwords match or a number is even.
The .check()
method, introduced in Zod 4, allows you to return multiple validation issues at once for better error reporting. While .superRefine()
previously provided contextual access for complex logic, it’s now deprecated in favor of .check()
.
These refinements make Zod highly extensible and ideal for enforcing business rules in TypeScript-based schema validation.
.refine()
– for simple post-validation logic.superRefine()
– granular access to the validation context [deprecated in zod 4].check()
– create multiple issues in a single refinement
Custom Error Messages: Supply second argument to .refine()
Transforms & Preprocessing in Zod
Zod supports powerful data transformation features to reshape input and output during validation. Use .transform()
to modify the result after successful parsing, and .preprocess()
to sanitize or convert raw input before validation runs.
For more complex workflows, .pipe()
lets you chain schemas with transformations, refinements, or validations in a clear, composable way. These tools are ideal for normalizing form data, formatting API responses, or handling custom logic during schema validation.
- .transform() – modify the output of a schema
- .preprocess() – sanitize or convert raw input before validation
- Pipes: Chain transforms and refinements with
.pipe()
Defaults, Optionals & Nullables in Zod
to allow undefined
, .nullable()
to allow null
, and nullish logic to accept both. The .default()
method assigns default values when a field is missing, while prefaults combine .optional().default()
for more control.
Explore more use cases in our complete guide to using .default()
in Zod schemas
Need defaults by type? See our guide on how to use .default()
with each Zod type →
For practical strategies on handling complex defaults efficiently, explore this guide to advanced default handling in Zod.
With .catch()
, you can recover from validation errors and provide fallback values at runtime. These features make it easy to manage optional, nullable, and defaultable fields in both TypeScript and JavaScript applications.
- Optionals:
z.string().optional()
- Nullables:
z.string().nullable()
- Nullish: Accepts both
null
andundefined
- Defaults:
z.string().default('tecktol')
- Prefaults: Use
.optional().default()
combo - Catch:
.catch()
to handle fallback value on failure
Special Types & Helpers in Zod
Zod offers several advanced schema types for specialized use cases. z.unknown()
accepts any value, making it useful for deferring validation. z.never()
matches no values and is ideal for enforcing exhaustive type checks.
Zod also supports readonly schemas to prevent object mutation, branded types using .brand()
for creating nominal typing, and simulates template literal types using refinements for pattern-based string validation.
These tools help developers handle edge cases while maintaining strong type safety and runtime guarantees.
- Unknown:
z.unknown()
accepts any value - Never:
z.never()
matches nothing (useful for exhaustive checks) - Readonly: Prevent modifications
- Branded types: Use
.brand()
for type-safe tagging - Template literals: (not native, but simulated via refinements)
Function Schemas & JSON in Zod
Zod allows you to validate function types using z.function()
, where you can strictly define the parameter types with .args()
and the return type with .returns()
. This ensures your functions conform to expected signatures at runtime.
For working with structured data, Zod supports recursive shapes to define valid JSON schemas — allowing you to handle deeply nested objects and arrays using z.lazy()
and unions. These features are essential when validating user-defined callbacks or parsing complex JSON data in TypeScript applications.
- Functions: Validate function types using
z.function()
- JSON: Define valid JSON schemas using recursive shapes
Shared Zod Schemas for Frontend and Backend Form Validation in a Monorepo
Using Zod, teams can define shared schemas to validate data consistently across both frontend and backend. In a monorepo setup, these schemas can be reused across multiple apps or services, ensuring type-safe form validation and reducing duplication. This approach improves reliability and maintainability in large projects.
Learn how to implement end-to-end form validation with Zod in a monorepo architecture for consistent and reliable input handling
Zod React Hook Form Integration
When you combine Zod with React Hook Form, you get the perfect balance of type-safe validation and lightweight form handling. This integration makes it easy to validate fields like strings, numbers, arrays, enums, files, and even async checks — all while keeping forms fast and scalable.
Explore the full guide on Zod React Hook Form
For advanced use cases, Zod also provides metadata and registries, which let you attach additional information to schemas and manage schema references programmatically. Learn more in our Zod Metadata & Registries guide.
Summary
Zod offers a vast set of features that cater to both beginner and advanced developers. From primitives to recursive objects and transformations, it helps keep your data validations tight and your TypeScript code clean.