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.
| TypeBox | Valibot |
|---|---|
Static | InferOutput |
StaticDecode | InferOutput |
StaticEncode | InferInput |
Type.Composite | Object merging |
Type.Integer | number with integer |
Type.KeyOf | keyof |
Type.Recursive | lazy |
Type.Transform | pipe with transform |
Type.Unsafe | custom |
TypeCompiler | parser, safeParser |
Value.Check | is |
Value.Decode | parse |
Value.Default | optional |
Value.Errors | safeParse |
Value.Parse | parse |
The same applies to the constraint options. The following table shows how they map to Valibot's actions.
| TypeBox | Valibot |
|---|---|
additionalProperties: false | strictObject |
additionalProperties: T | objectWithRest |
default | optional |
exclusiveMaximum | ltValue |
exclusiveMinimum | gtValue |
format | email, url, uuid and others |
maximum | maxValue |
maxItems | maxLength |
maxProperties | maxEntries |
minimum | minValue |
minItems | minLength |
minProperties | minEntries |
multipleOf | multipleOf |
pattern | regex |
uniqueItems | checkItems |
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.