# Migrate from Yup

> This document is the Markdown version of [valibot.dev/guides/migrate-from-yup/](https://valibot.dev/guides/migrate-from-yup/). For the complete documentation index, see [llms.txt](https://valibot.dev/llms.txt).

Migrating from [Yup](https://github.com/jquense/yup) to Valibot is straightforward in most cases since both APIs share the same basic concepts. The following guide will help you migrate step by step and also point out important differences.

## Replace imports

The first thing to do after [installing](/guides/installation.md) Valibot is to update your imports. Just change your Yup imports to Valibot's and replace all occurrences of `yup.` with `v.`.

```ts
// Change this
import * as yup from 'yup';
const Schema = yup.object({ key: yup.string().required() });

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

## Restructure code

One of the biggest differences between Yup and Valibot is the way you further validate a given type. In Yup, you chain methods like `.email` and `.max`. In Valibot you use [pipelines](/guides/pipelines.md) to do the same thing. This is a function that starts with a schema and is followed by up to 19 validation or transformation actions.

```ts
// Change this
const Schema = yup.string().email().max(30);

// To this
const Schema = v.pipe(v.string(), v.email(), v.maxLength(30));
```

Due to the modular design of Valibot, also all other methods like `.validate` or `.isValid` 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. Note that Yup's `.validate` method is asynchronous by default, whereas [`parse`](/api/parse.md) is synchronous.

```ts
// Change this
const value = yup.string().validateSync('foo');

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

We recommend that you read our [mental model](/guides/mental-model.md) guide to understand how the individual functions of Valibot's modular API work together.

## Required by default

Yup schemas are optional by default. To reject `undefined`, you have to append `.required()` to each schema. Valibot works the other way around. Every schema is required by default, and you explicitly mark schemas as optional by wrapping them with [`optional`](/api/optional.md), [`nullable`](/api/nullable.md) or [`nullish`](/api/nullish.md).

```ts
// Change this
const Schema = yup.object({
  name: yup.string().required(),
  email: yup.string(),
});

// To this
const Schema = v.object({
  name: v.string(),
  email: v.optional(v.string()),
});
```

There is one detail to watch out for. For string schemas, Yup's `.required()` also rejects empty strings. If you rely on this behavior, add the [`nonEmpty`](/api/nonEmpty.md) action to your pipeline.

```ts
// Change this
const Schema = yup.string().required();

// To this
const Schema = v.pipe(v.string(), v.nonEmpty());
```

## No implicit type coercion

Before validating a value, Yup casts it to the expected type. For example, `yup.number()` accepts the string `'24'` and converts it to the number `24`. This even applies to `.isValid` checks. Valibot never changes your data implicitly. If you rely on type coercion, use a pipeline with an explicit [`transform`](/api/transform.md) action or one of the dedicated transformation actions like [`toNumber`](/api/toNumber.md) or [`toDate`](/api/toDate.md). This forces you to explicitly define the input, resulting in safer code.

```ts
// Change this
const NumberSchema = yup.number();

// To this
const NumberSchema = v.pipe(v.string(), v.toNumber());
```

The same applies to dates. Yup's `.cast` method converts ISO strings to `Date` objects. In Valibot, you define this conversion explicitly.

```ts
// Change this
const DateSchema = yup.date();

// To this
const DateSchema = v.pipe(v.string(), v.toDate());
```

Keep in mind that [`toNumber`](/api/toNumber.md) behaves like JavaScript's `Number` function and therefore converts empty strings to `0`, and that [`toDate`](/api/toDate.md) accepts any string that the `Date` constructor can parse. For stricter validation, we recommend adding actions like [`decimal`](/api/decimal.md) or [`isoTimestamp`](/api/isoTimestamp.md) to validate the formatting of the string before converting it.

```ts
const NumberSchema = v.pipe(v.string(), v.decimal(), v.toNumber());
const DateSchema = v.pipe(v.string(), v.isoTimestamp(), v.toDate());
```

## Change names

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

| Yup            | Valibot                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| `bool`         | [`boolean`](/api/boolean.md)                                                                  |
| `concat`       | [Object merging](/guides/intersections.md#merge-objects)                                           |
| `default`      | [`optional`](/api/optional.md)                                                                |
| `InferType`    | [`InferOutput`](/api/InferOutput.md)                                                          |
| `isValid`      | [`is`](/api/is.md)                                                                            |
| `json`         | [`parseJson`](/api/parseJson.md)                                                              |
| `lessThan`     | [`ltValue`](/api/ltValue.md)                                                                  |
| `matches`      | [`regex`](/api/regex.md)                                                                      |
| `max`          | [`maxLength`](/api/maxLength.md), [`maxValue`](/api/maxValue.md)               |
| `min`          | [`minLength`](/api/minLength.md), [`minValue`](/api/minValue.md)               |
| `mixed`        | [`any`](/api/any.md), [`unknown`](/api/unknown.md)                             |
| `moreThan`     | [`gtValue`](/api/gtValue.md)                                                                  |
| `negative`     | [`ltValue`](/api/ltValue.md)                                                                  |
| `noUnknown`    | [`strictObject`](/api/strictObject.md)                                                        |
| `notOneOf`     | [`notValues`](/api/notValues.md)                                                              |
| `notRequired`  | [`nullish`](/api/nullish.md)                                                                  |
| `of`           | Item argument of [`array`](/api/array.md)                                                     |
| `oneOf`        | [`picklist`](/api/picklist.md)                                                                |
| `positive`     | [`gtValue`](/api/gtValue.md)                                                                  |
| `shape`        | `entries`                                                                                                    |
| `strip`        | [`omit`](/api/omit.md)                                                                        |
| `test`         | [`check`](/api/check.md), [`rawCheck`](/api/rawCheck.md)                       |
| `typeError`    | Error message argument of schema                                                                             |
| `validate`     | [`parseAsync`](/api/parseAsync.md), [`safeParseAsync`](/api/safeParseAsync.md) |
| `validateSync` | [`parse`](/api/parse.md), [`safeParse`](/api/safeParse.md)                     |

## Other details

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

### Unknown object keys

By default, Yup keeps unknown keys when validating objects. Valibot's [`object`](/api/object.md) schema removes them instead. If you rely on Yup's behavior, use [`looseObject`](/api/looseObject.md). If you use the `stripUnknown` option, [`object`](/api/object.md) is the right choice. To reject unknown keys, as with `.noUnknown()` in combination with `.strict()`, use [`strictObject`](/api/strictObject.md). See the [objects](/guides/objects.md) guide for more details.

```ts
// Change this
const ObjectSchema = yup.object({ key: yup.string().required() });

// To this
const ObjectSchema = v.looseObject({ key: v.string() });
```

### Cross-field validation

Yup uses `ref` to reference the value of another field, for example to check that two passwords match. In Valibot, you use a pipeline on the object schema with [`forward`](/api/forward.md) and [`partialCheck`](/api/partialCheck.md) instead.

```ts
// Change this
const RegisterSchema = yup.object({
  password: yup.string().required(),
  confirmPassword: yup
    .string()
    .required()
    .oneOf([yup.ref('password')], 'The two passwords do not match.'),
});

// To this
const RegisterSchema = v.pipe(
  v.object({
    password: v.pipe(v.string(), v.nonEmpty()),
    confirmPassword: v.pipe(v.string(), v.nonEmpty()),
  }),
  v.forward(
    v.partialCheck(
      [['password'], ['confirmPassword']],
      (input) => input.password === input.confirmPassword,
      'The two passwords do not match.'
    ),
    ['confirmPassword']
  )
);
```

### Conditional schemas

There is no direct equivalent to Yup's `.when()` method. For discriminated unions, we recommend [`variant`](/api/variant.md). For other conditional validations, you can use [`check`](/api/check.md) or [`rawCheck`](/api/rawCheck.md) on the parent object, or select the schema dynamically with [`lazy`](/api/lazy.md), which receives the current input as an argument.

### Error messages

Instead of `.typeError()` and per-validation message arguments, you pass a single string as the first argument to schemas and as the last argument to actions. See the [quick start](/guides/quick-start.md#error-messages) guide for more details.

```ts
// Change this
const Schema = yup
  .number()
  .typeError('Must be a number')
  .min(10, 'Number is too small');

// To this
const Schema = v.pipe(
  v.number('Must be a number'),
  v.minValue(10, 'Number is too small')
);
```

### Async validation

In Yup, `.validate` is always asynchronous. Valibot is synchronous by default and provides dedicated async functions like [`parseAsync`](/api/parseAsync.md), [`pipeAsync`](/api/pipeAsync.md) and [`checkAsync`](/api/checkAsync.md) for schemas that require asynchronous logic, such as database checks. See the [async guide](/guides/async-validation.md) for more details.
