Zod parse vs safeParse
Learn when to use Zod parse, safeParse, parseAsync, and safeParseAsync for TypeScript validation, API boundaries, forms, and error handling.
Quick answer: should you use parse or safeParse?
Use `parse` when invalid data should throw. Use `safeParse` when invalid data should become a normal control-flow branch. Both validate the same schema; the difference is whether failures throw a `ZodError` or return a result object.
Zod parse example
`parse` returns typed data when validation succeeds. When validation fails, it throws, so it works best in code paths where invalid input is exceptional and a central error handler can report the failure.
import { z } from "zod";
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
});
const user = UserSchema.parse(payload);
// user is typed as:
// { id: string; email: string }Handle a Zod parse error
When using `parse`, catch `ZodError` where you can add context, log the issue, or convert the failure into a controlled response. Avoid broad catch blocks that hide validation details.
try {
const user = UserSchema.parse(payload);
return user;
} catch (error) {
if (error instanceof z.ZodError) {
reportValidationError(error.issues);
}
throw error;
}Zod safeParse example
`safeParse` never throws for validation failures. It returns a result object, which makes it a better default for user input, request bodies, form submissions, and any flow that needs a predictable error response.
const result = UserSchema.safeParse(payload);
if (!result.success) {
return {
ok: false,
issues: result.error.issues,
};
}
return {
ok: true,
user: result.data,
};safeParse return type and TypeScript narrowing
The safeParse return type is a discriminated union. After checking `result.success`, TypeScript knows whether `result.data` or `result.error` is available, so callers do not need casts.
const result = UserSchema.safeParse(payload);
if (result.success) {
result.data.email.toLowerCase();
} else {
result.error.flatten().fieldErrors;
}parseAsync and safeParseAsync
Use the async variants when the schema uses asynchronous refinements or transforms. The error behavior stays the same: `parseAsync` throws, while `safeParseAsync` returns a success or error result.
const InviteSchema = z.object({
email: z.string().email(),
}).refine(async (value) => {
return await canInviteEmail(value.email);
}, "Email cannot receive invites");
const parsedInvite = await InviteSchema.safeParseAsync(payload);Where each method fits
The best method depends on who owns the input and how the caller should recover. API responses, request bodies, forms, config files, and internal transforms all have different failure expectations.
- Use `parse` for trusted config, internal code, and API response clients where invalid upstream data should fail fast.
- Use `safeParse` for request bodies, forms, route handlers, server actions, and recoverable UI states.
- Use `parseAsync` or `safeParseAsync` when refinements call a database, service, or other promise-returning check.
- Generate starter schemas with JSON to Zod, then choose parse or safeParse at the boundary that receives unknown data.
Common mistakes
Most production bugs come from using the right schema with the wrong failure mode. Treat the parse method as part of the API contract, not just a syntax choice.
- Do not use `parse` directly on user input unless an exception is the intended control flow.
- Do not read `result.data` before checking `result.success` after safeParse.
- Do not use sync `parse` or `safeParse` when the schema contains async refinements.
- Do not expose raw validation payloads in public API responses.
Zod parse vs safeParse comparison
| Method | What happens | Use when |
|---|---|---|
| parse | Returns typed data when validation succeeds and throws a ZodError when validation fails. | Invalid data is exceptional, such as trusted config, internal payloads, or fetch clients handled by an error boundary. |
| safeParse | Returns a discriminated result object with `success: true` and data, or `success: false` and a ZodError. | Invalid data is expected or recoverable, such as forms, API requests, route handlers, and user-facing validation. |
| parseAsync | Awaits async refinements or transforms and throws when validation fails. | The schema performs asynchronous checks and failures should be handled by try/catch or a central error layer. |
| safeParseAsync | Awaits async validation and returns the same success/error result shape as safeParse. | The schema performs async checks and callers need structured errors instead of thrown exceptions. |
Use FrameworkKit to generate the starter code, then review the output before shipping it in production.
Generate with the JSON to Zod schema generatorZod validation resources
JSON to Zod converter
Convert sample payloads into copy-ready Zod schemas and inferred TypeScript types in the browser.
JSON to Zod schema examples
Open realistic API and product payload examples before adapting the JSON to Zod schema output.
TypeScript to Zod Converter
Convert TypeScript interfaces and type aliases into Zod schemas when the source shape already lives in code.
Zod to JSON Schema Converter
Use the canonical online converter when an existing Zod schema needs JSON Schema, AJV, or OpenAPI output.
Validate API responses with Zod
Validate API responses, request bodies, and fetch boundaries with Zod schemas in TypeScript.
Zod safeParse
Validate unknown data without throwing, narrow the result type, and format safeParse errors.
Zod safeParse error messages
Format safeParse failures, field errors, and API validation responses in TypeScript.
Zod refine vs superRefine
Add custom validation, async checks, and field-level error paths after generating a starter schema.
Zod nativeEnum in Zod 4
Migrate z.nativeEnum patterns to z.enum, validate TypeScript enums, and avoid enum value mistakes.
Use JSON to Zod for form validation
Start from a submitted form payload, then add business rules such as email, length, and enum checks.
Zod to JSON Schema for OpenAPI
Publish Zod API schemas as OpenAPI-compatible contracts when teams need portable documentation.
ZodError flatten vs format
Shape validation errors with z.flattenError() for forms and z.treeifyError() for nested data in Zod 4.
Zod coerce for query params
Turn string query params and form fields into numbers, dates, and booleans, and avoid the coerce.boolean trap.
Zod email validation (z.email)
Validate emails with the top-level z.email() in Zod 4, add custom messages, and migrate off z.string().email().
Zod transform and pipe
Reshape validated data with transform, chain a second check with pipe, and use z.codec for reversible conversions.
Zod vs JSON Schema
Choose between TypeScript-first runtime validation and portable schema contracts.
Zod vs Yup vs Valibot
Compare TypeScript validation libraries for API boundaries, forms, server actions, and bundle tradeoffs.
FAQ
Does zod parse throw?
Yes. `schema.parse(input)` returns typed data when validation succeeds and throws a ZodError when validation fails.
What does safeParse return?
`safeParse` returns a discriminated result object: `success: true` with parsed data, or `success: false` with a ZodError.
When should I use safeParse?
Use `safeParse` when invalid input is expected or recoverable, such as form submissions, API request bodies, server actions, and UI validation flows.
Is safeParse slower than parse?
Both methods run the same schema validation. Choose based on error handling: thrown exceptions with `parse`, or a structured result object with `safeParse`.
When should I use parseAsync or safeParseAsync?
Use async parsing when the schema has asynchronous refinements or transforms. Choose `parseAsync` for thrown failures and `safeParseAsync` for structured result handling.
Related tools
TypeScript to Zod Converter
Convert TypeScript interfaces and type aliases into Zod schemas with inferred types in your browser.
Zod to JSON Schema Converter
Use a free browser-only online converter to turn Zod 4 schemas into JSON Schema for Draft 2020-12, Draft 7, AJV, or OpenAPI-compatible output.
OpenAPI to Zod
Turn OpenAPI schemas into Zod validators and lightweight typed fetch clients.