Migrate Yup to Zod

Zod has become the de facto standard for TypeScript schema validation thanks to its TypeScript-first design, superior type inference, and rapidly growing ecosystem. If your project uses Yup and you want better type safety, first-class TypeScript support, and compatibility with tools like tRPC, React Hook Form, and Next.js Server Actions, migrating to Zod is the natural next step.

Quick Start

Install SchemaShift and run the migration in two commands:

npm install -g schemashift-cli
# Migrate all Yup schemas to Zod
schemashift migrate ./src -f yup -t zod

Before & After

Here is a typical Yup schema and its Zod equivalent after migration:

Yup
import * as yup from 'yup';

const userSchema = yup.object({
  name: yup.string().required().min(2),
  email: yup.string().email().required(),
  age: yup.number().positive().integer(),
  role: yup.mixed().oneOf(['admin', 'user']),
});

type User = yup.InferType<typeof userSchema>;
Zod
import { z } from 'zod';

const userSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
  age: z.number().positive().int(),
  role: z.enum(['admin', 'user']),
});

type User = z.infer<typeof userSchema>;

Notice that Zod fields are required by default, so .required() is removed. .integer() becomes .int(), and yup.mixed().oneOf() becomes the more type-safe z.enum().

Common Conversion Patterns

Yup Zod Notes
yup.string() z.string() Direct equivalent
yup.number() z.number() No auto-coercion in Zod
yup.boolean() z.boolean() Direct equivalent
yup.date() z.date() Direct equivalent
yup.mixed() z.unknown() Zod has no untyped mixed
.required() (removed) Zod fields are required by default
.notRequired() .optional() Explicit opt-in for optional fields
.nullable() .nullable() Direct equivalent
.email() .email() Direct equivalent
.url() .url() Direct equivalent
.matches(regex) .regex(regex) Method name change
.integer() .int() Shortened method name
.positive() .positive() Direct equivalent
.oneOf([...]) z.enum([...]) Type-safe enum in Zod
.test(...) .refine(...) Arguments reordered (see gotchas)
InferType<...> z.infer<...> Type helper migration
yup.boolean().isTrue() z.literal(true) Boolean literal type
yup.boolean().isFalse() z.literal(false) Boolean literal type

Edge Cases & Gotchas

Automated Migration Command

SchemaShift provides several flags to control the migration process. Start with a dry run to preview changes before modifying any files:

# Dry run first
schemashift migrate ./src -f yup -t zod --dry-run

# Run migration with backup
schemashift migrate ./src -f yup -t zod

# With git branch isolation
schemashift migrate ./src -f yup -t zod --git-branch migrate/yup-to-zod

# Generate diff output
schemashift migrate ./src -f yup -t zod --dry-run --output-diff changes.diff

Manual Migration Checklist

After running the automated migration, review these items to ensure everything works correctly:

FAQ

How do I migrate from Yup to Zod?

Install SchemaShift CLI with npm install -g schemashift-cli, then run schemashift migrate ./src -f yup -t zod. The tool uses AST-based transformations to automatically convert Yup schemas to Zod equivalents, rewrite type helpers like InferType to z.infer, and update form library resolver imports. Always run with --dry-run first to preview changes. Every migration creates a timestamped backup that you can restore with schemashift rollback.

What Yup patterns are automatically converted?

SchemaShift automatically converts all common Yup patterns: string, number, boolean, date, array, and object schemas; validation methods like .email(), .url(), .min(), .max(), .matches(), .positive(), .integer(); .oneOf() to z.enum(); .test() to .refine(); .nullable() and .optional(); InferType to z.infer; and boolean literals .isTrue()/.isFalse() to z.literal(). It also handles the required/optional field semantics differences between the two libraries.

What needs manual review when migrating Yup to Zod?

Several patterns require manual review: Yup .when() conditionals have no direct Zod equivalent and need conversion to z.discriminatedUnion() or .superRefine(); Yup auto-coerces strings to numbers while Zod does not (use z.coerce.number() if needed); async .test() validators require switching call sites to .parseAsync(); and custom error message formats differ between libraries. SchemaShift adds TODO(schemashift) comments for all patterns requiring manual attention.

Related Migration Guides

Get Started

SchemaShift handles the tedious parts of migration so you can focus on reviewing edge cases. The Yup to Zod migration is available on the free tier.

npm install -g schemashift-cli

Need git integration or advanced analysis? View pricing.