Migrate from TypeBox

Migrating from TypeBox to Valibot is straightforward in most cases since both libraries are type-safe and share the same basic concepts. Like Valibot, TypeBox schemas are required by default, which makes the structure of your schemas easy to map. 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 Valibot is to update your imports. Since Valibot validates your data itself, the separate imports for the Value module or the TypeCompiler are no longer needed. To infer the type of a schema, replace Static with InferOutput.

// Change this
import { Type, type Static } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';
const Schema = Type.Object({ key: Type.String() });
type Data = Static<typeof Schema>;

// To this
import * as v from 'valibot';
const Schema = v.object({ key: v.string() });
type Data = v.InferOutput<typeof Schema>;

Restructure code

TypeBox describes constraints with a JSON Schema options object as the last argument. In Valibot you use pipelines 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.

// Change this
const Schema = Type.String({ minLength: 3, maxLength: 30 });

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

To validate or parse data, you pass the schema as the first argument to methods like is, parse or safeParse.

// Change this
const valid = Value.Check(Schema, input);

// To this
const valid = v.is(Schema, input);

We recommend that you read our mental model guide to understand how the individual functions of Valibot's modular API work together.

String formats

In TypeBox, string formats like email must be registered with the FormatRegistry before they can be used, or they will fail validation. Valibot ships these validations as actions that work out of the box.

// Change this
FormatRegistry.Set('email', (value) => isEmail(value));
const Schema = Type.String({ format: 'email' });

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

No implicit type conversion

TypeBox's Value.Parse runs the Clean, Default and Convert operations before asserting the type. This means that it removes unknown object keys and converts values to the expected type. For example, the string '24' is converted to the number 24. In Valibot, this behavior is not controlled by the parsing method, but by the schema itself. The object schema removes unknown keys and optional applies default values, but no schema ever converts types implicitly. If you rely on type conversion, use a pipeline with an explicit transform action or one of the dedicated transformation actions like toNumber or toDate. This forces you to explicitly define the input, resulting in safer code.

// Change this
const value = Value.Parse(Type.Number(), input);

// To this
const value = v.parse(v.pipe(v.string(), v.toNumber()), input);

Similarly, Type.Transform with its Decode and Encode functions is replaced by a pipeline with a transform action. Note that Valibot only transforms in one direction and does not provide an equivalent to Value.Encode.

// Change this
const Schema = Type.Transform(Type.String())
  .Decode((value) => new Date(value))
  .Encode((value) => value.toISOString());
const date = Value.Decode(Schema, input);

// To this
const Schema = v.pipe(v.string(), v.toDate());
const date = v.parse(Schema, input);

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

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

Change names

Many type builder functions just change to lowercase, such as Type.String to string or Type.Object to object. However, there are some exceptions. The following table shows all names that have changed beyond that.

TypeBoxValibot
StaticInferOutput
StaticDecodeInferOutput
StaticEncodeInferInput
Type.CompositeObject merging
Type.Integernumber with integer
Type.KeyOfkeyof
Type.Recursivelazy
Type.Transformpipe with transform
Type.Unsafecustom
TypeCompilerparser, safeParser
Value.Checkis
Value.Decodeparse
Value.Defaultoptional
Value.ErrorssafeParse
Value.Parseparse

The same applies to the constraint options. The following table shows how they map to Valibot's actions.

TypeBoxValibot
additionalProperties: falsestrictObject
additionalProperties: TobjectWithRest
defaultoptional
exclusiveMaximumltValue
exclusiveMinimumgtValue
formatemail, url, uuid and others
maximummaxValue
maxItemsmaxLength
maxPropertiesmaxEntries
minimumminValue
minItemsminLength
minPropertiesminEntries
multipleOfmultipleOf
patternregex
uniqueItemscheckItems

Other details

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

Unknown object keys

Following JSON Schema semantics, TypeBox allows and keeps unknown keys when validating objects by default. Valibot's object schema removes them instead, similar to Value.Clean. If you rely on TypeBox's behavior, use looseObject. To reject unknown keys, as with additionalProperties: false, use strictObject. See the objects guide for more details.

// Change this
const ObjectSchema = Type.Object(
  { key: Type.String() },
  { additionalProperties: false }
);

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

Unique items

Valibot does not provide a dedicated action for JSON Schema's uniqueItems keyword. Instead, you can use the checkItems action. Its requirement function receives the entire array as its third argument, which allows you to compare each item against the others.

// Change this
const Schema = Type.Array(Type.Number(), { uniqueItems: true });

// To this
const Schema = v.pipe(
  v.array(v.number()),
  v.checkItems(
    (item, index, array) => array.indexOf(item) === index,
    'Duplicate items are not allowed'
  )
);

Reusable parsers

TypeBox's TypeCompiler generates optimized JavaScript code for a schema at runtime. Valibot's schemas are executed directly and do not require a compile step. This also means that Valibot does not evaluate generated code, which allows it to run in environments with a strict Content Security Policy. If you like the ergonomics of a compiled validator, parser and safeParser create a reusable function bound to your schema.

// Change this
const Compiled = TypeCompiler.Compile(Schema);
const valid = Compiled.Check(input);

// To this
const parseSchema = v.safeParser(Schema);
const result = parseSchema(input);

JSON Schema

TypeBox schemas are JSON Schema objects. Valibot schemas are plain JavaScript objects with their own structure. If you need JSON Schema output, for example for OpenAPI definitions or LLM structured outputs, you can use the official @valibot/to-json-schema package to convert your Valibot schemas to JSON Schema. See the JSON Schema guide for more details.

import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';

const ValibotSchema = v.object({
  name: v.string(),
  email: v.pipe(v.string(), v.email()),
});

const jsonSchema = toJsonSchema(ValibotSchema);

Async validation

Unlike TypeBox, Valibot also supports asynchronous validation, for example for database checks. See the async guide for more details.

Contributors

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

  • 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 @vasilii-kovalev
  • GitHub profile picture of @UpwayShop
  • GitHub profile picture of @ruiaraujo012
  • GitHub profile picture of @hyunbinseo
  • GitHub profile picture of @nickytonline
  • GitHub profile picture of @kibertoad
  • GitHub profile picture of @caegdeveloper
  • GitHub profile picture of @Thanaen
  • GitHub profile picture of @bmoyroud
  • GitHub profile picture of @ysknsid25
  • GitHub profile picture of @dslatkin