Valorm is a lightweight, TypeScript-first validation library for turning unknown data into safe, typed data.
Think of it like:
βTake messy input β validate it β get clean, typed output.β
Valorm is built for modern apps that need validation without bloat.
- Tiny bundle size (~2.6KB gzipped)
- Minimal runtime overhead
- No unnecessary abstractions
- Optimized parsing pipeline
- Efficient runtime checks
- Great for frontend + serverless environments
Valorm gives you only what you actually need:
- Chainable schemas
- Strong TypeScript inference
- Safe parsing APIs
- Flexible composition
Nothing extra. Nothing heavy.
npm install valorm
# or
pnpm add valorm
# or
bun add valormimport { v, Infer } from "valorm";
const UserSchema = v.object({
id: v.string().uuid(),
email: v.string().trim().email(),
age: v.number().int().nonnegative().optional(),
isAdmin: v.boolean().default(false),
});
type User = Infer<typeof UserSchema>;
const user = UserSchema.parse({
id: "550e8400-e29b-41d4-a716-446655440000",
email: " user@example.com ",
});
console.log(user);import { v } from "valorm";
const UserSchema = v.object({
email: v.string().email(),
});
const result = UserSchema.safeParse({ email: "bad-email" });
if (!result.success) {
console.log(result.error.issues);
}- Returns validated data
- Throws on failure
schema.parse(data);- Never throws
- Returns structured result
const result = schema.safeParse(data);
if (!result.success) {
console.log(result.error);
}Extracts the TypeScript type from a schema.
type User = Infer<typeof UserSchema>;v.string().min(3).max(20).email();Methods:
coerce()trim()min(),max(),length()email(),url(),uuid()regex()startsWith(),endsWith()nonempty()
v.number().int().positive();Methods:
coerce()min(),max(),gt(),lt()int(),positive(),negative(),nonnegative()multipleOf()
v.boolean().coerce();Supports:
"true","false"1,0
v.date().min(new Date("2026-01-01"));Accepts:
- Date
- string
- timestamp
v.literal("admin");v.enum(["draft", "published"] as const);Accepts anything.
Always fails validation.
const User = v.object({
id: v.string(),
email: v.string().email(),
});- default β strips unknown keys
strict()β throws on unknown keyspassthrough()β keeps unknown keys
User.pick("id");
User.omit("email");
User.partial();
User.extend({ age: v.number() });
User.merge(OtherSchema);v.array(v.string()).min(1).max(10);v.tuple([v.number(), v.number()]);v.record(v.number());v.union([v.string(), v.number()]);v.discriminatedUnion("type", [
v.object({ type: v.literal("a") }),
v.object({ type: v.literal("b") }),
]);v.intersection(A, B);Works on all schemas:
v.string().optional();v.string().nullable();v.number().default(10);v.number().refine(n => n % 2 === 0, "Must be even");v.string().transform(s => s.toUpperCase());import { ValidationError } from "valorm";
try {
schema.parse(data);
} catch (err) {
if (err instanceof ValidationError) {
console.log(err.issues);
}
}{
path: (string | number)[];
message: string;
received?: unknown;
}Comparison with Zod:
| Library | Gzipped |
|---|---|
| Valorm | ~2.6KB πͺΆ |
| Zod | ~59KB |
| Operation | Valorm | Zod |
|---|---|---|
| Simple validation | β‘ Fast | β‘ Fast |
| Object parsing | β‘ Lightweight | β‘ Heavier |
| Cold start | πͺΆ Low impact | π Higher |
- πͺΆ Smaller footprint
- β‘ Fast validation
- π§© Minimal API
- π Modern app focused
const Post = v.object({
title: v.string().min(3),
body: v.string().min(20),
status: v.enum(["draft", "published"]).default("draft"),
tags: v.array(v.string()).default(() => []),
});
const result = Post.safeParse({
title: "Hello",
body: "This is a valid post body...",
});
if (result.success) {
console.log(result.data);
}- Object schemas strip unknown keys by default
nullable()behavior may evolve- Some custom messages still improving (WIP)
vβ schema builderSchemaβ base classValidationErrorInfer<T>
npm run build
npm run typecheckValorm is built for:
- β‘ speed
- π§ clarity
- π developer experience
If you know Zod, youβll feel right at home β just lighter, faster, and simpler.
Do less. Stay fast. Keep it simple.