Migrate Joi to Zod

Joi was built for JavaScript and lacks native TypeScript type inference. Zod is TypeScript-first, providing automatic type inference with z.infer, a smaller bundle size, and first-class support in modern frameworks like tRPC, React Hook Form, and Next.js. This guide covers every step of the migration.

Quick Start

Install SchemaShift and run the migration in two commands:

npm install -g schemashift-cli

schemashift migrate ./src -f joi -t zod

This analyzes every file in ./src, rewrites Joi schemas to Zod, updates imports, and creates backup files automatically.

Before & After

Joi (before)
import Joi from 'joi';

const userSchema = Joi.object({
  name: Joi.string().required().min(2),
  email: Joi.string().email().required(),
  port: Joi.number().port(),
  role: Joi.string().valid('admin', 'user')
});
Zod (after)
import { z } from 'zod';

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

type User = z.infer<typeof userSchema>;

Notice how Zod gives you the User type for free — no separate interface to maintain.

Conversion Reference

Complete mapping from Joi methods to their Zod equivalents. SchemaShift handles all of these automatically.

Joi Zod Notes
Joi.string() z.string()
Joi.number() z.number()
Joi.boolean() z.boolean()
Joi.date() z.date()
Joi.any() z.unknown() Prefer z.unknown() over z.any() for type safety
Joi.binary() z.instanceof(Buffer) Node.js only
.required() (removed) Zod fields are required by default
.optional() .optional()
.allow(null) .nullable()
.forbidden() z.never()
.email() .email()
.uri() .url()
.uuid() .uuid()
.ip() .ip()
.pattern(regex) .regex(regex)
.alphanum() .regex(/^[a-zA-Z0-9]+$/) No built-in Zod equivalent
.greater(n) .gt(n)
.less(n) .lt(n)
.port() .int().min(0).max(65535) No built-in port validator in Zod
.valid(...) z.enum([...]) For string literals
.invalid(...) .refine() Custom validation needed
.custom(fn) .refine(fn)
Joi.alternatives() z.union()

Edge Cases & Gotchas

These Joi patterns have no direct Zod equivalent and require manual attention. SchemaShift generates scaffolding code and inline TODO comments for each one.

Automated Migration Commands

Preview changes without modifying any files:

schemashift migrate ./src -f joi -t zod --dry-run

Run the full migration with verbose output:

schemashift migrate ./src -f joi -t zod --verbose

Generate a unified diff for code review:

schemashift migrate ./src -f joi -t zod --dry-run --output-diff changes.patch

Migrate with a Git branch for easy rollback:

schemashift migrate ./src -f joi -t zod --git-branch migrate/joi-to-zod
Backup included

SchemaShift creates automatic backups before modifying files. Use schemashift rollback to restore originals at any time.

Manual Migration Checklist

After running the automated migration, review these items:

Frequently Asked Questions

Can I automatically convert Joi schemas to Zod?

Yes. SchemaShift provides an AST-based CLI that automatically converts Joi schemas to Zod, including import rewriting, method chain transformation, and type helper migration. Run schemashift migrate ./src -f joi -t zod to convert an entire directory. Unsupported patterns receive inline TODO comments with actionable guidance.

What Joi features are not directly supported in Zod?

Joi's .when() conditional validation, .with() / .without() field dependencies, .and() / .nand() / .or() / .xor() group constraints, and Joi.ref() cross-field references have no direct Zod equivalents. These are migrated to .superRefine() or .refine() patterns in Zod, with SchemaShift generating scaffolding code and TODO comments for manual review.

Why should I migrate from Joi to Zod?

Zod is TypeScript-first and provides automatic type inference via z.infer, eliminating the need to maintain separate TypeScript interfaces. Zod has a smaller bundle size, faster validation performance, and a growing ecosystem with first-class support in tRPC, React Hook Form, and Next.js. Joi was designed for JavaScript and lacks native TypeScript type inference.

Related Migration Guides

Ready to migrate?

Convert your Joi schemas to Zod in minutes. Free to use.

npm install -g schemashift-cli
Read the Docs View Pricing