Zod vs Yup for TypeScript Validation

By James Nguyen Updated September 24, 2026
Zod vs Yup for TypeScript Validation

An older project on my team has used Yup with Formik since before I joined, and a newer service I started from scratch uses Zod, which gave me an unusually direct basis for comparing them rather than relying on secondhand impressions. Both do the same fundamental job, validating data at runtime and giving you a TypeScript type back, but living with each day to day surfaced real differences.

Type Inference Is the Whole Story With Zod

Zod's core pitch, define a schema once and derive the TypeScript type from it with z.infer, rather than maintaining a separate interface and a separate validator that can drift apart, is the single biggest reason I'd pick it for anything new. On the Zod-based service, changing a schema field automatically updates every place that imports the inferred type, and the compiler catches the mismatch immediately if a consumer isn't updated to match.

const UserSchema = z.object({
  email: z.string().email(),
  age: z.number().int().positive(),
});
type User = z.infer;

Yup's Type Support Was Bolted On, and It Shows

Yup predates the point where TypeScript-first design was the default assumption for a new validation library, and its type inference, while it exists and has improved, still occasionally requires manual type annotations that Zod's z.infer never needs. On the older Formik-plus-Yup codebase, I've hit cases where the inferred type from a Yup schema didn't quite match what I expected and needed a manual override, something that essentially never comes up on the Zod side.

Error Formatting: Zod's ZodError Is More Structured

Zod's error objects come back as a structured ZodError with a path array pinpointing exactly which nested field failed and why, which mapped cleanly onto per-field form error messages without extra transformation code. Yup's errors are usable but required a bit more manual mapping in our older codebase to get the same per-field granularity in the UI.

Yup's Async Validation Is Genuinely Better

This is the one area where Yup has a real edge: its .test() validators support async functions natively as a first-class pattern, which our older codebase leans on for things like checking username availability against the database during form validation. Zod supports async refinements too, but the ergonomics felt less natural to me, more like an accommodation than the primary design case, when I tried porting one of these checks over as an experiment.

Formik Integration Still Favors Yup

If a codebase is already built on Formik, Yup remains the path of least resistance, since Formik's own documentation and examples are written with Yup in mind, and the yupResolver pattern is thoroughly battle-tested at this point. React Hook Form, by contrast, documents Zod prominently through @hookform/resolvers, and most new form-heavy projects I've seen or worked on recently default to that pairing rather than Formik plus Yup.

Bundle Size Wasn't Actually a Deciding Factor for Us

Zod's bundle size has historically been criticized relative to newer, more minimal alternatives, and while that's a legitimate concern for a bundle-size-sensitive edge function, for our two applications, both fairly conventional server-rendered and client apps, it never showed up as a measurable problem in our bundle analysis, so it wasn't a real factor in either direction here.

Migrating the Old Codebase Isn't Happening Soon

Despite preferring Zod for new work, migrating the Yup-based codebase isn't on our roadmap, because it works, the team knows it, and a validation library swap across a codebase with years of accumulated Formik-plus-Yup forms is a lot of risk for a benefit that's mostly about developer experience rather than user-facing functionality. This is the honest calculus a lot of "just migrate to the newer library" advice skips over.

Sharing Schemas Between Frontend and Backend

The Zod-based service validates the same schema on both the API route handling incoming requests and the frontend form submitting them, importing the identical schema object on both sides through a shared package. On the Yup-based codebase, frontend and backend validation logic drifted apart more than once, a max-length rule updated on the server without the corresponding Formik form catching up, something the shared-schema approach makes structurally harder to happen by accident.

Refinements and Custom Validation Logic

Beyond basic type checks, both libraries support custom validation, Zod's .refine() and .superRefine() versus Yup's .test(), for rules that don't fit a built-in validator, like confirming a password field matches a confirmation field. Zod's refinement API felt more composable when I needed to chain several custom checks together with distinct error messages, while Yup's equivalent worked fine for a single custom rule but got harder to read once we stacked more than two or three on the same field.

What a Fresh Team Member Notices First

New hires who'd used Zod before consistently ramped up faster on the Zod-based service than on the Yup-based one, mostly because they could trust the inferred type without cross-referencing a separate interface definition to check it was current. That's a soft, hard-to-quantify signal, but it showed up consistently enough across a few onboarding cycles that I now mention it directly when anyone asks which library to pick for a new project.

Final Verdict

For a new TypeScript project, Zod's type inference alone is enough to make it the default choice, and the ecosystem, tRPC, React Hook Form's documentation, most new starter templates, has largely settled around it too. Yup isn't obsolete, its async validation story is genuinely better and its Formik integration is more mature, but that's a reason to leave a working Yup codebase alone, not a reason to choose it fresh in 2026.

Daniel Justin

About the Author

James Nguyen is a full-stack programmer with more than ten years of experience engineering software systems. Specializing in the Node.js and Python ecosystems, he focuses on backend architecture, API design, and clean data integration. Follow me on YouTube and Instagram.

More Articles