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 a success 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.

TypeScriptZod
Avatar for Niall Maher

Written by Niall Maher

Founder of Codú - The web developer community! I've worked in nearly every corner of technology businesses; Lead Developer, Software Architect, Product Manager, CTO and now happily a Founder.

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.