My core functionality is to create a schema that describes a structured data set. 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 * as v from 'valibot';

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

// Valibot
const LoginSchema = v.object({
  email: v.string(),
  password: v.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 * as v from 'valibot';

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

Pipelines 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 create a SchemaIssue with various details and an error message. This error message can be overridden via the first optional argument of a schema or validation function.

import * as v from 'valibot';

const LoginSchema = v.object({
  email: v.string('Your email must be a string.', [
    v.minLength(1, 'Please enter your email.'),'The email address is badly formatted.'),
  password: v.string('Your password must be a string.', [
    v.minLength(1, 'Please enter your password.'),
    v.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. See the i18n guide for more information.

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.

import * as v from 'valibot';

const BigintSchema = v.bigint(); // bigint
const BooleanSchema = v.boolean(); // boolean
const NullSchema = v.null_(); // null
const NumberSchema = v.number(); // number
const StringSchema = v.string(); // string
const SymbolSchema = v.symbol(); // symbol
const UndefinedSchema = v.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 pick, partial and merge. Learn more about them here.

import * as v from 'valibot';

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

Special cases

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

import * as v from 'valibot';

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


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

  • GitHub profile picture of fabian-hiller
  • GitHub profile picture of alonidiom
  • GitHub profile picture of yicrotkd
  • GitHub profile picture of blueaelixir


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


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