@schemashift/yup-zod
v0.14.0
Published
Yup ↔ Zod bidirectional transformer for SchemaShift
Maintainers
Readme
@schemashift/yup-zod
Yup ↔ Zod transformer for SchemaShift. Supports both forward (Yup → Zod) and backward (Zod → Yup) migrations.
Installation
npm install @schemashift/yup-zodUsage
import { createYupToZodHandler, createZodToYupHandler } from '@schemashift/yup-zod';
import { TransformEngine } from '@schemashift/core';
const engine = new TransformEngine();
engine.registerHandler('yup', 'zod', createYupToZodHandler());
engine.registerHandler('zod', 'yup', createZodToYupHandler()); // Backward migration (Pro+)Backward Migration: Zod → Yup
AST-based transformer that converts Zod schemas back to Yup equivalents:
| Zod | Yup |
|-----|-----|
| z.object({...}) | yup.object({...}) |
| z.string() | yup.string() |
| z.number() | yup.number() |
| z.boolean() | yup.boolean() |
| z.date() | yup.date() |
| z.array(s) | yup.array().of(s) |
| .optional() | .notRequired() |
| .nullable() | .nullable() |
| .refine(fn, msg) | .test('custom', msg, fn) |
| z.enum([...]) | yup.mixed().oneOf([...]) |
| z.union([...]) | yup.mixed().oneOf([...]) |
| z.literal(val) | yup.mixed().oneOf([val]) |
| z.record(k, v) | yup.object() (with TODO) |
| z.tuple([...]) | yup.array() (with TODO) |
Tier: Pro+
Transformation Mappings
Imports
| Yup | Zod |
|-----|-----|
| import * as yup from 'yup' | import { z } from 'zod' |
| import yup from 'yup' | import { z } from 'zod' |
Basic Types
| Yup | Zod |
|-----|-----|
| yup.string() | z.string() |
| yup.number() | z.number() |
| yup.boolean() | z.boolean() |
| yup.date() | z.date() |
| yup.array() | z.array() |
| yup.object() | z.object() |
| yup.mixed() | z.unknown() |
Required/Optional
| Yup | Zod | Notes |
|-----|-----|-------|
| .required() | (removed) | Zod fields are required by default |
| .notRequired() | .optional() | |
| .nullable() | .nullable() | |
| .defined() | (removed) | Handled by Zod's type system |
String Validations
| Yup | Zod |
|-----|-----|
| .email() | .email() |
| .url() | .url() |
| .uuid() | .uuid() |
| .min(n) | .min(n) |
| .max(n) | .max(n) |
| .length(n) | .length(n) |
| .matches(regex) | .regex(regex) |
| .lowercase() | .toLowerCase() |
| .uppercase() | .toUpperCase() |
| .trim() | .trim() |
Number Validations
| Yup | Zod |
|-----|-----|
| .min(n) | .min(n) |
| .max(n) | .max(n) |
| .positive() | .positive() |
| .negative() | .negative() |
| .integer() | .int() |
Array Validations
| Yup | Zod |
|-----|-----|
| .min(n) | .min(n) |
| .max(n) | .max(n) |
| .length(n) | .length(n) |
| .of(schema) | z.array(schema) |
Object Methods
| Yup | Zod |
|-----|-----|
| .shape({...}) | z.object({...}) |
| .pick([...]) | .pick({...}) |
| .omit([...]) | .omit({...}) |
| .partial() | .partial() |
| .strict() | .strict() |
| .passthrough() | .passthrough() |
Other
| Yup | Zod |
|-----|-----|
| .default(value) | .default(value) |
| .oneOf([...]) | z.enum([...]) or z.literal().or(...) |
| .test(...) | .refine(...) |
| .transform(...) | .transform(...) |
Patterns Requiring Manual Review
The transformer generates actionable .superRefine() scaffolding for these patterns (not bare TODOs):
.when() Conditionals
Yup's .when() doesn't have a direct Zod equivalent. The transformer generates a .superRefine() template with the original condition context:
// Yup
const schema = yup.object({
isBusiness: yup.boolean(),
companyName: yup.string().when('isBusiness', {
is: true,
then: yup.string().required(),
}),
});
// Generated output (with scaffolding)
/* TODO(schemashift): Convert conditional validation.
Original: .when('isBusiness', { is: true, then: ..., otherwise: ... })
Suggested Zod equivalent:
.superRefine((data, ctx) => {
if (data.isBusiness === true) {
// Apply 'then' validation
} else {
// Apply 'otherwise' validation
}
})
*/
const schema = z.object({
isBusiness: z.boolean(),
companyName: z.string().optional(),
}).superRefine((data, ctx) => {
if (data.isBusiness && !data.companyName) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Company name required for business accounts',
path: ['companyName'],
});
}
});.test() Custom Validations
Complex .test() calls may need adjustment for Zod's .refine() API.
// Yup
yup.string().test('custom', 'Invalid', (value) => customValidation(value))
// Zod
z.string().refine((value) => customValidation(value), 'Invalid')Async Validations
Yup supports async validation in .test(). Zod requires explicit async handling.
// Yup
yup.string().test('unique', 'Already exists', async (value) => {
return await checkUnique(value);
})
// Zod
z.string().refine(async (value) => {
return await checkUnique(value);
}, 'Already exists')
// Note: Use .parseAsync() instead of .parse()Related Packages
- schemashift-cli — CLI tool for running migrations
- @schemashift/core — Core analysis engine
- @schemashift/zod-valibot — Chain: Yup → Zod → Valibot
- @schemashift/zod-v3-v4 — Upgrade Zod after migration
License
MIT
