Overview
Zod provides two methods for custom validation:.refine()- Simple custom validation with a boolean check.superRefine()- Advanced validation with full control over error messages and multiple issues
.refine()
Add custom validation logic with a simple check function.Signature
(data) => boolean | Promise<boolean>
required
Function that returns
true if validation passes, false if it failsstring | RefinementOptions
Error message string or options object
Basic Usage
Custom Error Paths
Specify which field the error applies to:Async Refinements
.superRefine()
Advanced validation with full control over error reporting.Signature
Output
required
The validated data
RefinementCtx
required
Context object with
addIssue() methodBasic Usage
Adding Issues
Thectx.addIssue() method accepts several forms:
Full Issue Object
String Shorthand
Refinement Options
Error Messages
Error Paths
Aborting Validation
Stop validation on first error:Fatal Flag
Similar toabort, but set on the issue:
Continue Flag
Control whether subsequent refinements run:Conditional Refinements
Use thewhen option to conditionally run refinements:
Type Narrowing
Type Guard Refinements
Use type guards to narrow the output type:Non-Type-Guard Refinements
Regular refinements don’t narrow types:Common Patterns
Either/Or Fields
Cross-Field Validation
Unique Array Elements
Complex Business Rules
Async Database Validation
Multiple Validation Rules
Chaining Refinements
You can chain multiple refinements:Error Examples
Basic Refinement Error
SuperRefine Multiple Errors
Best Practices
Use refine for simple checks
Use
.refine() when you just need a true/false validation. It’s simpler and more readable.Use superRefine for complex validation
Use
.superRefine() when you need multiple errors, custom error codes, or fine control over error paths.Provide helpful error messages
Error messages should clearly explain what’s wrong and how to fix it.
Set appropriate paths
Point errors to the specific field that’s invalid using the
path option.Consider performance
Refinements run after schema validation. Expensive checks (like database calls) should be async and may benefit from caching.
Validate early
Use base schema validation for simple checks. Reserve refinements for complex business logic that requires multiple fields.
Comparison
See Also
- Transform - Data transformation
- Pipe - Chain schemas
- Custom Errors - Error handling guide
- Async Validation - Async validation patterns