Zod parse versus safeParse - What's the Difference?
Zod offers two ways to parse your data to check for errors:
.parse and .safeParse (they also have async varieties with .parseAsync and .safeParseAsync.
So what's the difference?
- Zod
.parse: Throws an error if validation fails. This is useful when you want to immediately stop execution and handle the error centrally, such as within a middleware or a try-catch block. - Zod
.safeParse: Does not error, but returns an object with asuccessboolean property and, based on that, either the validated data or the validation error.
To understand it, I always think it makes sense to see it in action:
Example
Let's define a simple UserSchema with a name (string) and age (number):
import { z } from 'zod';
const UserSchema = z.object({
name: z.string(),
age: z.number(),
});
Now we can look at the differences:
Zod parse
You can use the .parse method on a schema to validate data. This method throws an error if the data doesn't match the schema.
So a try/catch becomes important:
try {
const user = UserSchema.parse({ name: "Jane Doe", age: 30 });
console.log("Valid user:", user);
} catch (error) {
console.error("Validation failed:", error);
}
Now let's look at how you would handle a .safeParse:
Zod safeParse
safeParse can be useful if you prefer handling validation results without using try-catch blocks. It's a little more verbose so let's look at both a valid and invalid flow.
First, let's look at a valid value:
const result = UserSchema.safeParse({ name: "John Doe", age: 30 });
// result equals: { success: true; data: { name: "John Doe", age: 30 }
if (result.success) {
// result.succes === true, so we end up here
console.log("Valid user:", result.data);
} else {
console.error("Validation failed:", result.error);
}
Now, let's look at a invalid value:
// Setting age to a string
const result = UserSchema.safeParse({ name: "John Doe", age: "thirty" });
// result equals: { success: false; error: ZodError }
if (result.success) {
console.log("Valid user:", result.data);
} else {
// result.succes === false, so we end up here
console.error("Validation failed:", result.error);
}
I like to handle my errors in try/catches, but as you can see, both can be used to achieve the same results.
