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 asuccess
boolean 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.