My core functionality is to create a schema. A schema can be compared to a type definition in TypeScript. The big difference is that TypeScript types are "not executed" and are more or less a DX feature. A schema on the other hand, apart from the inferred type definition, can also be executed at runtime to guarantee type safety of unknown data.

Until I reach v1, I welcome lots of feedback on the API, naming and implementation. Please create or reply to an issue and help me become the best schema library for JavaScript and TypeScript.

How it works

Similar to how types can be defined in TypeScript, my source code allows you to define a schema with various small functions. This applies to primitive values like strings as well as to more complex data sets like objects.

import { object, string } from 'valibot'; // 0.86 kB

// TypeScript
type LoginForm = {
  email: string;
  password: string;

// Valibot
const LoginSchema = object({
  email: string(),
  password: string(),


In addition, I can help you to perform more detailed validations and transformations with pipelines. Thus, for example, it can be ensured that a string is an email and ends with a certain domain.

import { email, endsWith, string } from 'valibot'; // 0.7 kB

const EmailSchema = string([email(), endsWith('')]);

Pipeline are optional and, if needed, are always added in the form of an array as the last argument of a schema function. More details about pipelines can be found in this guide.

Error messages

If I detect an issue during validation, I throw a ValiError and add a short error message to each issue. This error message can be overridden via the first optional argument of a schema or validation function.

import { email, minLength, object, string } from 'valibot'; // 1.06 kB

const LoginSchema = object({
  email: string('Your email must be a string.', [
    minLength(1, 'Please enter your email.'),
    email('The email address is badly formatted.'),
  password: string('Your password must be a string.', [
    minLength(1, 'Please enter your password.'),
    minLength(8, 'Your password must have 8 characters or more.'),

Custom error messages allow you to improve the usability of your software by providing specific troubleshooting information and returning error messages in a language other than English.

Primitive values

I support the creation of schemas for any primitive data type. These are immutable values that are stored directly in the stack, unlike objects where only a reference to the heap is stored.

Due to the modular design, occasionally reserved keywords of JavaScript or TypeScript get in my way. As a workaround, I have added the suffix _ in these cases. Let me know here if you have alternative ideas.

Schema functions: bigint, boolean, null_, number, string, symbol, undefined_

const BigintSchema = bigint(); // bigint
const BooleanSchema = boolean(); // boolean
const NullSchema = null_(); // null
const NumberSchema = number(); // number
const StringSchema = string(); // string
const SymbolSchema = symbol(); // symbol
const UndefinedSchema = undefined_(); // undefined

Complex values

Among complex values I support objects, records, arrays, tuples as well as various other classes.

For objects I provide various methods like partial and merge. Learn more about them here.

Schema functions: array, blob, date, map, object, record, set, tuple

const ArraySchema = array(string()); // string[]
const BlobSchema = blob(); // Blob
const DateSchema = date(); // Date
const MapSchema = map(string(), number()); // Map<string, number>
const ObjectSchema = object({ key: string() }); // { key: string }
const RecordSchema = record(number()); // Record<string, number>
const SetSchema = set(number()); // Set<number>
const TupleSchema = tuple([string(), number()]); // [string, number]

Special cases

Beyond primitive and complex values, I also provide schema functions for more special cases.

Schema functions: any, enum_, instance, intersect, nan, never, nonNullable, nonNullish, nonOptional,nullable, nullish, optional, picklist, recursive, special, union, unknown, variant, void_

const AnySchema = any(); // any
const InstanceSchema = instance(Error); // Error
const IntersectSchema = intersect([string(), literal('a')]); // string & 'a'
const NanSchema = nan(); // NaN
const EnumSchema = enum_(Direction); // Direction
const NeverSchema = never(); // never
const NonNullableSchema = nonNullable(nullable(string())); // string
const NonNullishSchema = nonNullish(nullish(string())); // string
const NonOptionalSchema = nonOptional(optional(string())); // string
const NullableSchema = nullable(string()); // string | null
const NullishSchema = nullish(string()); // string | null | undefined
const OptionalSchema = optional(string()); // string | undefined
const PicklistSchema = picklist(['a', 'b']); // 'a' | 'b'
const RecursiveSchema = recursive(() => string()); // string
const SpecialSchema = special<`${number}px`>(isPixelString); // `${number}px`
const UnionSchema = union([string(), number()]); // string | number
const UnknownSchema = unknown(); // unknown
const VariantSchema = variant('type', [
  object({ type: literal('a'), foo: string() }),
  object({ type: literal('b'), bar: number() }),
]); // { type: 'a', foo: string } | { type: 'b', bar: number }
const VoidSchema = void_(); // void