valibot
Validates data with Valibot's modular, tree-shakable schema library for minimal bundle size. Use when bundle size matters, building form validation, or needing lightweight TypeScript validation.
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Valibot
Modular schema validation library with best-in-class bundle size (~1KB for basic forms).
Quick Start
npm install valibot
import * as v from 'valibot';
const schema = v.object({
name: v.pipe(v.string(), v.minLength(2)),
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.minValue(0)),
});
// Validate
const result = v.safeParse(schema, data);
if (result.success) {
console.log(result.output);
} else {
console.log(result.issues);
}
Schema Types
Primitives
import * as v from 'valibot';
// String
v.string()
v.pipe(v.string(), v.minLength(1), v.maxLength(100))
// Number
v.number()
v.pipe(v.number(), v.minValue(0), v.maxValue(100))
// Boolean
v.boolean()
// Null/Undefined
v.null_()
v.undefined_()
// BigInt
v.bigint()
// Symbol
v.symbol()
// Date
v.date()
v.pipe(v.date(), v.minValue(new Date()))
String Validations
v.pipe(
v.string(),
v.minLength(1, 'Required'),
v.maxLength(100, 'Too long'),
v.email('Invalid email'),
v.url('Invalid URL'),
v.uuid('Invalid UUID'),
v.regex(/^[a-z]+$/, 'Only lowercase'),
v.startsWith('https://'),
v.endsWith('.com'),
v.includes('@'),
v.trim(),
v.toLowerCase(),
v.toUpperCase(),
)
Number Validations
v.pipe(
v.number(),
v.minValue(0, 'Must be positive'),
v.maxValue(100, 'Max 100'),
v.integer('Must be integer'),
v.multipleOf(5, 'Must be multiple of 5'),
v.finite('Must be finite'),
v.safeInteger('Must be safe integer'),
)
Object
const userSchema = v.object({
name: v.string(),
email: v.pipe(v.string(), v.email()),
age: v.optional(v.number()),
});
// Strict (no extra keys)
const strictSchema = v.strictObject({
id: v.number(),
name: v.string(),
});
// Loose (allow extra keys)
const looseSchema = v.looseObject({
id: v.number(),
});
Array
v.array(v.string())
v.pipe(
v.array(v.string()),
v.minLength(1, 'At least one item'),
v.maxLength(10, 'Max 10 items'),
)
// Tuple
v.tuple([v.string(), v.number()])
Union & Intersection
// Union (OR)
const statusSchema = v.union([
v.literal('active'),
v.literal('inactive'),
v.literal('pending'),
]);
// Variant (discriminated union)
const eventSchema = v.variant('type', [
v.object({ type: v.literal('click'), x: v.number(), y: v.number() }),
v.object({ type: v.literal('scroll'), offset: v.number() }),
]);
// Intersection (AND)
const combined = v.intersect([
v.object({ id: v.number() }),
v.object({ name: v.string() }),
]);
Optional & Nullable
// Optional (undefined allowed)
v.optional(v.string())
// Nullable (null allowed)
v.nullable(v.string())
// Nullish (null or undefined)
v.nullish(v.string())
// With default
v.optional(v.string(), 'default value')
v.nullable(v.number(), 0)
Pipe System
Valibot uses pipe() to chain validations and transformations:
const schema = v.pipe(
v.string(),
v.trim(), // Transform
v.minLength(1), // Validate
v.toLowerCase(), // Transform
v.email(), // Validate
);
// Order matters!
const result = v.parse(schema, ' John@Example.COM ');
// Output: 'john@example.com'
Validation
parse() - Throws on Error
try {
const data = v.parse(schema, input);
} catch (error) {
if (error instanceof v.ValiError) {
console.log(error.issues);
}
}
safeParse() - Returns Result
const result = v.safeParse(schema, input);
if (result.success) {
console.log(result.output);
} else {
console.log(result.issues);
}
is() - Type Guard
if (v.is(schema, input)) {
// input is typed
}
Type Inference
import * as v from 'valibot';
const userSchema = v.object({
id: v.number(),
name: v.string(),
email: v.pipe(v.string(), v.email()),
roles: v.array(v.string()),
});
// Infer TypeScript type
type User = v.InferOutput<typeof userSchema>;
// { id: number; name: string; email: string; roles: string[] }
// Infer input type (before transforms)
type UserInput = v.InferInput<typeof userSchema>;
Custom Validation
check() - Custom Predicate
const schema = v.pipe(
v.string(),
v.check((value) => value.includes('@'), 'Must contain @'),
);
transform() - Custom Transform
const schema = v.pipe(
v.string(),
v.transform((value) => value.split(',').map((s) => s.trim())),
);
Custom Schema
const passwordSchema = v.pipe(
v.string(),
v.minLength(8, 'At least 8 characters'),
v.regex(/[A-Z]/, 'Need uppercase'),
v.regex(/[a-z]/, 'Need lowercase'),
v.regex(/[0-9]/, 'Need number'),
);
Common Patterns
User Registration
const registrationSchema = v.object({
email: v.pipe(
v.string(),
v.email('Invalid email'),
),
password: v.pipe(
v.string(),
v.minLength(8, 'At least 8 characters'),
v.regex(/[A-Z]/, 'Need uppercase'),
v.regex(/[0-9]/, 'Need number'),
),
confirmPassword: v.string(),
age: v.pipe(
v.number(),
v.minValue(18, 'Must be 18+'),
),
terms: v.pipe(
v.boolean(),
v.value(true, 'Must accept terms'),
),
});
// Add cross-field validation
const fullSchema = v.pipe(
registrationSchema,
v.forward(
v.partialCheck(
[['password'], ['confirmPassword']],
(input) => input.password === input.confirmPassword,
'Passwords must match',
),
['confirmPassword'],
),
);
API Response
const apiResponseSchema = v.object({
success: v.boolean(),
data: v.optional(v.object({
users: v.array(v.object({
id: v.number(),
name: v.string(),
})),
})),
error: v.optional(v.string()),
});
Environment Variables
const envSchema = v.object({
NODE_ENV: v.picklist(['development', 'production', 'test']),
PORT: v.pipe(v.string(), v.transform(Number), v.integer()),
DATABASE_URL: v.pipe(v.string(), v.url()),
API_KEY: v.pipe(v.string(), v.minLength(32)),
});
const env = v.parse(envSchema, process.env);
React Hook Form Integration
import { useForm } from 'react-hook-form';
import { valibotResolver } from '@hookform/resolvers/valibot';
import * as v from 'valibot';
const schema = v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
});
type FormData = v.InferOutput<typeof schema>;
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: valibotResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input {...register('password')} type="password" />
{errors.password && <span>{errors.password.message}</span>}
<button type="submit">Submit</button>
</form>
);
}
Bundle Size Comparison
| Library | Basic Form |
|---|---|
| Valibot | ~1.4 KB |
| Zod | ~12 KB |
| Yup | ~15 KB |
Valibot achieves this through modular imports - only used functions are bundled.
See references/methods.md for complete method reference.
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-01-20
- Mise à jour de l’index
- 2026-01-28
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!