Migrate from Zod

Migrating from Zod to Valibot is very easy in most cases since both APIs have a lot of similarities. The following guide will help you migrate step by step and also point out important differences.

If anything is unclear or missing, please create an issue on GitHub. We are very interested in making this guide as good as possible.

Replace imports

The first thing to do after installing Valibot is to update your imports. Just change your Zod imports to Valibot's and replace all occurrences of z. with v..

// Change this
import { z } from 'zod';
const Schema = z.object({ key: z.string() });

// To this
import * as v from 'valibot';
const Schema = v.object({ key: v.string() });

Restructure code

One of the biggest differences between Zod and Valibot is the way you further validate a given type. In Zod, you chain methods like .email and .endsWith. In Valibot you use pipelines to do the same thing. This is an array of validation and transformation actions defined as the last argument of a schema function.

// Change this
const Schema = z.string().email().endsWith('@example.com');

// To this
const Schema = v.string([v.email(), v.endsWith('@example.com')]);

Due to the modular design of Valibot, also all other methods like .parse or .safeParse have to be used a little bit differently. Instead of chaining them, you usually pass the schema as the first argument and move any existing arguments one position to the right.

// Change this
const value = z.string().parse('foo');

// To this
const value = v.parse(v.string(), 'foo');

Change names

Most of the names are the same as in Zod. However, there are some exceptions. The following table shows all names that have changed.

ZodValibot
andintersect
catchfallback
catchallobject
customspecial
datetimeisoDate, isoDateTime
defaultoptional
discriminatedUnionvariant
elementitem
enumpicklist
extendmerge
gt, gteminValue
inferOutput
intinteger
inputInput
instanceofinstance
intersectionintersect
lt, ltemaxValue
maxmaxLength, maxSize, maxValue
minminLength, minSize, minValue
nativeEnumenum_
negativemaxValue
nonnegativeminValue
nonpositivemaxValue
nullnull_
orunion
outputOutput
passthroughobject
positiveminValue
refinecustom
resttuple
safesafeInteger
shapeentries
strictobject
stripobject
trimtoTrimmed
undefinedundefined_
voidvoid_

Other details

Below are some more details that may be helpful when migrating from Zod to Valibot.

Object and tuple

To specify whether object or tuple should allow or prevent unknown values, Valibot uses the rest parameter. Zod uses the methods .passthrough, .strict, .strip, .catchall and .rest instead. See the objects and arrays guide for more details.

// Change this
const ObjectSchema = z.object({ key: z.string() }).strict();

// To this
const ObjectSchema = v.object({ key: v.string() }, v.never());

Error messages

For individual error messages, you can pass a string or an object to Zod. It also allows you to differentiate between an error message for "required" and "invalid_type". With Valibot you just pass a single string instead.

// Change this
const SchemaSchema = z
  .string({ invalid_type_error: 'Not a string' })
  .min(5, { message: 'Too short' });

// To this
const StringSchema = v.string('Not a string', [v.minLength(5, 'Too short')]);

Coerce type

To enforce primitive values, you can use a method of the coerce object in Zod. In Valibot, coerce is a function that works similar to transform, but is executed before validation. More information can be found here.

// Change this
const NumberSchema = z.coerce.number();

// To this
const NumberSchema = v.coerce(v.number(), Number);

Async validation

Similar to Zod, Valibot support synchronous and asynchronous validation. However, the API is a little bit different. See the async guide for more details.

Contributors

Thanks to all the contributors who helped make this page better!

  • GitHub profile picture of morinokami
  • GitHub profile picture of fabian-hiller

Partners

Thanks to our partners who support the project ideally and financially.

Sponsors

Thanks to our GitHub sponsors who support the project financially.

  • GitHub profile picture of dailydotdev
  • GitHub profile picture of ivan-mihalic
  • GitHub profile picture of KATT
  • GitHub profile picture of osdiab
  • GitHub profile picture of Thanaen
  • GitHub profile picture of ruiaraujo012
  • GitHub profile picture of hyunbinseo
  • GitHub profile picture of caegdeveloper