Zod parse vs safeParse - Choosing the Right One

September 11, 2024

Zod is a powerful schema validation library that offers two primary methods to validate data: .parse and .safeParse. Both can be used synchronously or asynchronously (.parseAsync and .safeParseAsync), depending on your needs.

Define A Schema:

We’ll create a schema for a product, which includes a name, price, stock quantity, and a category.

product-schema.ts
import { z } from 'zod';
const productSchema = z.object({
name: z.string(),
price: z.number().positive(),
stock: z.number().int().nonnegative(),
category: z.enum(['Electronics', 'Books', 'Clothing', 'Toys']),
});

Zod Parse:

.parse: Immediate Error Throwing

The .parse method is straightforward—it throws an error if the data doesn’t match the schema. This is useful when you want the program to halt immediately upon invalid input, such as when validating input in middleware or inside a try-catch block

index.ts
try {
const productData = productSchema.parse({
name: "Laptop",
price: -1200, // Invalid: price should be positive
stock: 10,
category: "Electronics",
});
console.log("Validated Product:", productData);
} catch (error) {
console.error("Error:", error.errors);
}

Output:

Terminal
Error: [
{
"message": "Number must be greater than 0",
"path": ["price"],
"code": "too_small"
}
]

In this example, the price field is invalid because it’s negative, so .parse throws an error and halts the execution. This is helpful if you’re validating data at an API endpoint and want to reject the request immediately if it’s invalid.

Zod safeParse:

.safeParse: Graceful Error Handling

index.ts
const result = productSchema.safeParse({
name: "Laptop",
price: -1200, // Invalid: price should be positive
stock: 10,
category: "Electronics",
});
if (!result.success) {
console.error("Validation failed:", result.error.errors);
} else {
console.log("Validated Product:", result.data);
}

Output:

Terminal
Validation failed: [
{
"message": "Number must be greater than 0",
"path": ["price"],
"code": "too_small"
}
]

In this case, .safeParse doesn’t throw an error, but it returns an object indicating whether validation succeeded. The rest of your code can continue running even when validation fails.

Conclusion:

  • .parse: Useful for strict validation where you need to throw an error and stop execution when the data is invalid, such as in API requests.

  • .safeParse: Provides a non-throwing validation method, ideal for cases where you want to handle errors gracefully, like in form validation or non-blocking flows.

Zoom overlay