@oxog/vld
v2.1.0
Published
Ultra-fast TypeScript-first schema validation with zero dependencies, 27+ language support, plugin system, and CLI tools
Maintainers
Readme
VLD - Fast & Lightweight TypeScript Validation Library
VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScript with Zod-compatible root and subpath APIs. Built with performance in mind, it provides a simple and intuitive API while maintaining excellent type inference and 27+ language internationalization support.
Table of Contents
- Features
- Performance
- Installation
- Quick Start
- API Reference
- Internationalization (i18n)
- Error Handling & Formatting
- Advanced Examples
- Why VLD?
- Codecs - Bidirectional Transformations
- Plugin System
- Result Pattern
- CLI Tools
- Migrating from Zod
- Benchmarks
- Contributing
- Links
Features
Core Features
- Blazing Fast: Optimized for V8 engine with superior performance
- Type-Safe: Full TypeScript support with excellent type inference
- Zero Dependencies: Lightweight with no external dependencies
- Tree-Shakeable: Only import what you need
- Composable: Chain validations for complex schemas
- Advanced Error Formatting: Tree, pretty, and flatten error utilities
- Multi-language: Built-in support for 27+ languages
- 100% Statement / Branch / Line Coverage: Rigorously tested with 2160 passing tests
- Release-Gated Performance: CI guards require VLD to stay faster than the latest stable Zod across runtime, startup, and memory benchmarks
- Drop-in App Verification: A real TypeScript fixture is compiled and run once with
zodand once with built VLD, then normalized runtime output is compared
Advanced Zod-Compatible Features
- Type Coercion:
v.coerce.string(),v.coerce.number(),v.coerce.boolean(), etc. - Advanced Types: BigInt, Symbol, Tuple, Record, Set, Map validation
- Intersection Types: Combine multiple schemas with intelligent merging
- Custom Validation:
refine()for custom predicates and validation logic - Data Transformation:
transform()for post-validation data transformation - Default Values:
default()for handling undefined inputs elegantly - Fallback Handling:
catch()for graceful error recovery - Object Utilities:
pick(),omit(),extend()for flexible object schemas
NEW in v2.0.0 - Modular Architecture
Tree-Shakable Mini API
import { string, number, object, optional } from '@oxog/vld/mini';
const schema = object({
name: string().min(1),
age: optional(number().positive()),
});- 82% smaller bundles when using only needed validators
- Individual factory functions for optimal tree-shaking
- Full TypeScript support with identical type inference
Lazy Locale Loading
import { setLocaleAsync } from '@oxog/vld/locales';
await setLocaleAsync('tr'); // Loads Turkish on demand- 92% bundle reduction - Only English bundled by default
preloadLocales()for SSR/batch loading- Full backwards compatibility with
setLocale()
Dual ESM/CJS Build
- ESM builds for modern bundlers (Vite, esbuild)
- CJS builds for Node.js and legacy environments
- Proper
exportsfield with conditional exports
NEW in v1.5.0 - Major Platform Release
Plugin System
definePlugin(): Create custom plugins with validators, transforms, and codecsusePlugin(): Register plugins globally- Plugin Hooks: Lifecycle hooks for validation events
- Custom Validators: Extend VLD with your own validators
Result Pattern
Ok()/Err(): Functional error handlingmatch(): Pattern matching on resultsmap()/flatMap(): Transform resultstryCatch(): Safe function executionall(): Combine multiple results
Event System
createEmitter(): Type-safe event emittercreateEventBus(): Global event bus- Validation Events: Parse start, success, error, field validation
CLI Tools
vld validate: Validate data from command linevld benchmark: Run performance benchmarks- Colored Output: Beautiful terminal output with pigment
New Validators
v.discriminatedUnion(): Discriminated union typesv.xor(): Exclusive OR validationv.file(): File upload validationv.function(): Function validationv.custom(): Type-safe custom validatorsv.json(): JSON string validation with schemav.lazy(): Recursive schema supportv.nan(): NaN validationv.null(): Null validationv.undefined(): Undefined validationv.templateLiteral(): Template literal types
New String Format Validators
v.hostname(): Hostname validationv.emoji(): Emoji validationv.base64()/v.base64url(): Base64 format validationv.hex(): Hex string validationv.jwt(): JWT format validationv.nanoid()/v.cuid()/v.cuid2()/v.ulid(): ID format validationv.mac(): MAC address validationv.cidrv4()/v.cidrv6(): CIDR block validationv.e164(): E.164 phone number validationv.hash(): Hash validation (md5, sha1, sha256, sha384, sha512)v.iso.date()/v.iso.time()/v.iso.dateTime()/v.iso.duration(): ISO format validation
Enhanced Object Utilities
v.strictObject(): Strict mode object validationv.looseObject(): Passthrough object validationv.partialRecord(): Partial record validationv.looseRecord(): Loose record validationv.int(): Integer shortcutv.int32(): 32-bit integer shortcutv.nullish(): Null or undefinedv.NEVER: NEVER constant for transforms (Zod 4 parity)
Codec System - Beyond Zod
- Bidirectional Transformations: Full encode/decode support for data conversion
- 19 Built-in Codecs: String conversions, date parsing, JSON, URL, binary data
- Zod-Compatible: All
stringToNumber,jsonCodec,base64ToBytes, etc. - Async Support: Both sync and async codec operations
- Custom Codecs: Create your own bidirectional transformations
- Type-Safe: Full TypeScript support with perfect type inference
Performance
VLD is designed for speed and efficiency with recent optimizations delivering exceptional performance:
Release-Gated Speed Benchmarks (v2.1.0 vs Zod 4.4.3)
- Runtime guard: VLD must stay at least 1.2x faster on every guarded hot path and keep at least a 3x average ratio
- Startup guard: VLD must keep at least 1.1x faster import, 1.25x faster total startup, and 1.25x faster warm parse ratios than Zod
- Memory guard: VLD must keep at least 2x lower total retained heap, 1.5x higher aggregate throughput, and no guarded case below 1.1x speed
Recent Local Benchmark Snapshot
- 52.92x faster for nullish validation
- 46.58x faster for catch validation
- 27.62x faster for number validation
- 14.88x faster for bigint validation
- 10.71x faster for nullable validation
- Over 10x faster average guarded runtime ratio in recent release checks
Optimizations
- 110x improvement in union type validation
- Simplified email regex for maximum performance
- Inline type checks in object validation
- Optimized loops with direct array assignment
- SafeParse optimization to avoid try-catch overhead
- Pre-computed keys with Set for O(1) lookups
Memory Efficiency
- 18.13x less memory for schema creation
- 6.20x less memory for union validation
- 2.81x less memory for simple string validation
- 4.85x less memory overall
A Note on Real-World Benchmarking
Many validation library benchmarks can be misleading because they often test with reused schema instances:
// What benchmarks typically test (unrealistic):
const schema = z.string();
for (let i = 0; i < 1000000; i++) {
schema.parse(data); // Same instance reused
}
// What happens in real applications:
app.post('/api/user', (req, res) => {
// New schema created for each request
const schema = z.object({
email: z.string().email(),
age: z.number().min(18)
});
schema.parse(req.body);
});When testing real-world patterns:
- Creating new instances: VLD is 2000x faster than Zod
- Reused instances: Zod benefits from V8's singleton optimization
- Real applications: Schemas are often created dynamically, where VLD excels
Run npm run benchmark:truth to see the real performance difference.
Installation
npm install @oxog/vld
# or
yarn add @oxog/vld
# or
pnpm add @oxog/vldQuick Start
import { v } from '@oxog/vld';
// It is recommended to import as `v` for consistency with Zod's `z`
// and for a more concise syntax.
// Define a schema
const userSchema = v.object({
name: v.string().min(2),
email: v.string().email(),
age: v.number().min(18).max(100),
isActive: v.boolean()
});
// Validate data
const result = userSchema.safeParse({
name: 'John Doe',
email: '[email protected]',
age: 25,
isActive: true
});
if (result.success) {
console.log('Valid user:', result.data);
} else {
console.log('Validation error:', result.error);
}For advanced error formatting:
import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';API Reference
Basic Types
v.string() // String validation
v.number() // Number validation
v.int() // Integer validation (shortcut)
v.int32() // 32-bit integer validation
v.boolean() // Boolean validation
v.bigint() // BigInt validation
v.symbol() // Symbol validation
v.date() // Date validation
v.uint8array()// Uint8Array validation
v.literal() // Literal values
v.enum() // Enum values (supports TypeScript enums)
v.any() // Any type
v.unknown() // Unknown type
v.void() // Void type
v.never() // Never type
v.null() // Null type
v.undefined() // Undefined type
v.nan() // NaN typeAdvanced Types
// Collections
v.array(v.string()) // Array validation
v.tuple(v.string(), v.number()) // Fixed-length tuple
v.record(v.number()) // Record/dictionary validation
v.set(v.string()) // Set validation
v.map(v.string(), v.number()) // Map validation
// Objects
v.object({ // Object schema
name: v.string(),
age: v.number()
})
v.strictObject({...}) // No extra fields allowed
v.looseObject({...}) // Extra fields passed through
// Composition
v.union(v.string(), v.number()) // Union types
v.intersection(schemaA, schemaB) // Intersection types
v.discriminatedUnion('type', ...) // Discriminated union
v.xor(schemaA, schemaB) // Exclusive OR
v.optional(v.string()) // Optional fields
v.nullable(v.string()) // Nullable fields
v.nullish(v.string()) // Null or undefinedString Validators
v.string()
.min(5) // Minimum length
.max(10) // Maximum length
.length(8) // Exact length
.email() // Email format
.url() // URL format
.uuid() // UUID format
.regex(/pattern/) // Custom regex
.startsWith('prefix') // String prefix
.endsWith('suffix') // String suffix
.includes('substring') // Contains substring
.ip() // IP address (v4 or v6)
.trim() // Trim whitespace
.toLowerCase() // Convert to lowercase
.toUpperCase() // Convert to uppercase
.nonempty() // Non-empty stringString Format Validators (Top-Level)
v.email() // Email validation
v.uuid() // UUID validation
v.uuid({ version: 'v4' }) // UUID v4 validation
v.uuidv4() // UUID v4 shortcut
v.hostname() // Hostname validation
v.emoji() // Emoji validation
v.base64() // Base64 format
v.base64url() // Base64 URL-safe format
v.hex() // Hex string
v.jwt() // JWT format
v.nanoid() // NanoID format
v.cuid() // CUID format
v.cuid2() // CUID2 format
v.ulid() // ULID format
v.ipv4() // IPv4 address
v.ipv6() // IPv6 address
v.mac() // MAC address
v.cidrv4() // IPv4 CIDR block
v.cidrv6() // IPv6 CIDR block
v.e164() // E.164 phone number
v.hash('sha256') // Hash validation
v.iso.date() // ISO date format
v.iso.time() // ISO time format
v.iso.dateTime() // ISO datetime format
v.iso.duration() // ISO duration formatNumber Validators
v.number()
.min(0) // Minimum value
.max(100) // Maximum value
.int() // Integer only
.positive() // Positive numbers
.negative() // Negative numbers
.nonnegative() // >= 0
.nonpositive() // <= 0
.finite() // Finite numbers
.safe() // Safe integers
.multipleOf(5) // Multiple of valueArrays and Objects
// Arrays
v.array(v.string()) // Array of strings
.min(1) // Minimum length
.max(10) // Maximum length
.length(5) // Exact length
.nonempty() // Non-empty array
// Objects
v.object({
name: v.string(),
age: v.number()
})
.partial() // All fields optional
.strict() // No extra fields
.passthrough() // Allow extra fieldsComposite Types
// Optional
v.optional(v.string()) // string | undefined
// Nullable
v.nullable(v.string()) // string | null
// Nullish
v.nullish(v.string()) // string | null | undefined
// Union
v.union(v.string(), v.number()) // string | number
// Discriminated Union
v.discriminatedUnion('type',
v.object({ type: v.literal('a'), a: v.string() }),
v.object({ type: v.literal('b'), b: v.number() })
)
// Literal
v.literal('active') // 'active'
// Enum
v.enum('red', 'green', 'blue') // 'red' | 'green' | 'blue'Type Coercion
// Coerce strings from various types
v.coerce.string().parse(123) // "123"
v.coerce.string().parse(true) // "true"
// Coerce numbers from strings/booleans
v.coerce.number().parse("123") // 123
v.coerce.number().parse(true) // 1
// Coerce booleans from strings/numbers
v.coerce.boolean().parse("true") // true
v.coerce.boolean().parse(1) // true
// Coerce BigInt from strings/numbers
v.coerce.bigint().parse("123") // 123n
v.coerce.bigint().parse(456) // 456n
// Coerce Date from strings/timestamps
v.coerce.date().parse("2023-01-01") // Date object
v.coerce.date().parse(1672531200000) // Date objectObject Schema Methods
const userSchema = v.object({
name: v.string(),
age: v.number(),
email: v.string(),
role: v.string()
});
// Pick specific fields
const publicSchema = userSchema.pick('name', 'age');
// Type: { name: string; age: number }
// Omit sensitive fields
const safeSchema = userSchema.omit('email', 'role');
// Type: { name: string; age: number }
// Extend with new fields
const extendedSchema = userSchema.extend({
isActive: v.boolean(),
lastLogin: v.date()
});
// Type: { name: string; age: number; email: string; role: string; isActive: boolean; lastLogin: Date }Advanced Validation Methods
// Custom validation with refine()
const positiveNumber = v.number()
.refine(n => n > 0, "Number must be positive");
// Data transformation with transform()
const uppercaseString = v.string()
.transform(s => s.toUpperCase());
// Default values for undefined
const withDefault = v.string().default("fallback");
withDefault.parse(undefined); // "fallback"
// Catch errors and provide fallback
const withCatch = v.number().catch(-1);
withCatch.parse("invalid"); // -1
// Method chaining
const complexSchema = v.string()
.min(3)
.transform(s => s.trim())
.refine(s => s.includes('@'), 'Must contain @')
.default('[email protected]');Special Validators
// JSON validator with optional schema
v.json() // Any valid JSON
v.json(v.object({ name: v.string() })) // Typed JSON
// Lazy for recursive schemas
const categorySchema = v.lazy(() =>
v.object({
name: v.string(),
children: v.array(categorySchema).optional()
})
);
// Custom validator
v.custom({
check: (val) => typeof val === 'string' && val.length > 0,
message: 'Must be a non-empty string'
});
// File validator
v.file()
.maxSize(5 * 1024 * 1024) // 5MB
.type(['image/png', 'image/jpeg']);
// Function validator
v.function()
.args(v.string(), v.number())
.returns(v.boolean());Type Inference
import { v } from '@oxog/vld';
import type { Infer } from '@oxog/vld';
const schema = v.object({
name: v.string(),
age: v.number()
});
// Automatically infer the type
type User = Infer<typeof schema>;
// { name: string; age: number }Error Formatting Types
import { VldError } from '@oxog/vld';
import type {
VldIssue, // Individual validation issue
VldErrorTree, // Nested error structure
VldFlattenedError // Flattened error structure
} from '@oxog/vld';Custom Error Messages
const schema = v.string().min(8, 'Password must be at least 8 characters');
const result = schema.safeParse('short');
if (!result.success) {
console.log(result.error.message); // 'Password must be at least 8 characters'
}Internationalization (i18n)
VLD supports 27+ languages out of the box with comprehensive error messages:
import { v, setLocale } from '@oxog/vld';
// Default is English
const schema = v.string().min(5);
schema.safeParse('Hi'); // Error: "String must be at least 5 characters"
// Switch to Turkish
setLocale('tr');
schema.safeParse('Hi'); // Error: "Metin en az 5 karakter olmali"
// Switch to Spanish
setLocale('es');
schema.safeParse('Hi'); // Error: "La cadena debe tener al menos 5 caracteres"
// Switch to Japanese
setLocale('ja');
schema.safeParse('Hi'); // Error: "..."Supported Languages
Base Languages (15):
- English (
en) - Turkish (tr) - Spanish (es) - French (fr) - German (de) - Italian (
it) - Portuguese (pt) - Russian (ru) - Japanese (ja) - Korean (ko) - Chinese (
zh) - Arabic (ar) - Hindi (hi) - Dutch (nl) - Polish (pl)
European Languages (4):
- Danish (
da) - Swedish (sv) - Norwegian (no) - Finnish (fi)
Asian Languages (4):
- Thai (
th) - Vietnamese (vi) - Indonesian (id) - Bengali (bn)
African Languages (2):
- Swahili (
sw) - Afrikaans (af)
American Languages (2):
- Portuguese Brazil (
pt-BR) - Spanish Mexico (es-MX)
Plus 75+ additional languages supported through comprehensive type definitions with English fallback.
Error Handling & Formatting
VLD provides advanced error formatting utilities similar to Zod's error handling system.
Error Formatting Utilities
import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
const userSchema = v.object({
username: v.string().min(3),
favoriteNumbers: v.array(v.number()),
profile: v.object({
name: v.string(),
email: v.string().email()
})
});
const result = userSchema.safeParse({
username: 'ab',
favoriteNumbers: [1, 'two', 3],
profile: {
name: '',
email: 'invalid-email'
},
extraField: 'not allowed'
});
if (!result.success) {
const error = result.error as VldError;
// 1. Tree Format - Nested structure for complex UIs
const tree = treeifyError(error);
// 2. Pretty Format - Human-readable console output
const pretty = prettifyError(error);
// 3. Flatten Format - Simple form validation
const flattened = flattenError(error);
}Using Error Formats in Practice
React Form Validation
function UserForm() {
const [errors, setErrors] = useState<VldFlattenedError | null>(null);
const handleSubmit = (data: unknown) => {
const result = userSchema.safeParse(data);
if (!result.success) {
setErrors(flattenError(result.error as VldError));
} else {
setErrors(null);
}
};
return (
<form onSubmit={handleSubmit}>
{errors?.formErrors.map(error => (
<div key={error} className="form-error">{error}</div>
))}
<input name="username" />
{errors?.fieldErrors.username?.map(error => (
<div key={error} className="field-error">{error}</div>
))}
</form>
);
}API Error Responses
app.post('/api/users', (req, res) => {
const result = userSchema.safeParse(req.body);
if (!result.success) {
const tree = treeifyError(result.error as VldError);
res.status(400).json({
error: 'Validation failed',
details: tree
});
}
});Advanced Examples
Complex Validation with New Features
const postSchema = v.object({
id: v.union(v.string().uuid(), v.number()),
title: v.string().min(5).max(100),
content: v.string().min(10),
author: v.object({
name: v.string(),
email: v.string().email(),
age: v.coerce.number(),
}),
tags: v.set(v.string()).default(new Set()),
metadata: v.record(v.any()),
coordinates: v.tuple(v.number(), v.number()),
publishedAt: v.date().default(() => new Date()),
status: v.enum('draft', 'published', 'archived')
});
// Extend with additional fields
const blogPostSchema = postSchema.extend({
viewCount: v.bigint().default(0n),
categories: v.array(v.string()).min(1),
featured: v.boolean().default(false)
});Discriminated Union
const eventSchema = v.discriminatedUnion('type',
v.object({
type: v.literal('click'),
x: v.number(),
y: v.number()
}),
v.object({
type: v.literal('scroll'),
direction: v.enum('up', 'down'),
distance: v.number()
}),
v.object({
type: v.literal('keypress'),
key: v.string(),
modifiers: v.array(v.enum('ctrl', 'alt', 'shift'))
})
);
// Type-safe parsing
const event = eventSchema.parse({
type: 'click',
x: 100,
y: 200
});Recursive Schemas
const categorySchema: ReturnType<typeof v.lazy> = v.lazy(() =>
v.object({
name: v.string(),
slug: v.string().regex(/^[a-z0-9-]+$/),
children: v.array(categorySchema).optional()
})
);
const category = categorySchema.parse({
name: 'Electronics',
slug: 'electronics',
children: [
{
name: 'Phones',
slug: 'phones',
children: [
{ name: 'Smartphones', slug: 'smartphones' }
]
}
]
});Type-Safe Forms
const loginSchema = v.object({
username: v.string().min(3),
password: v.string().min(8),
rememberMe: v.optional(v.boolean())
});
type LoginForm = Infer<typeof loginSchema>;
function handleLogin(data: unknown) {
const result = loginSchema.safeParse(data);
if (result.success) {
const { username, password, rememberMe } = result.data;
// ... handle login
}
}Codecs - Bidirectional Transformations
VLD introduces codecs - powerful bidirectional transformations that can convert data between different representations.
What are Codecs?
Codecs enable safe, type-checked conversions between different data formats:
import { stringToNumber, jsonCodec, base64ToBytes } from '@oxog/vld';
// String to number conversion
const age = stringToNumber.parse('25'); // 25
const price = stringToNumber.encode(99.99); // "99.99"
// JSON codec
const userJson = jsonCodec();
const user = userJson.parse('{"name":"John","age":30}');
const jsonString = userJson.encode(user);
// Binary data
const bytes = base64ToBytes.parse('SGVsbG8gV29ybGQ=');Built-in Codecs
String Conversion Codecs
import { stringToNumber, stringToInt, stringToBigInt, stringToBoolean } from '@oxog/vld';
stringToNumber.parse('42.5'); // 42.5
stringToInt.parse('42'); // 42
stringToBigInt.parse('123n'); // 123n
stringToBoolean.parse('true'); // trueDate Conversion Codecs
import { isoDatetimeToDate, epochSecondsToDate, epochMillisToDate } from '@oxog/vld';
isoDatetimeToDate.parse('2023-12-25T10:30:00.000Z'); // Date
epochSecondsToDate.parse(1703505000); // Date
epochMillisToDate.parse(1703505000000); // DateURL Codecs
import { stringToURL, stringToHttpURL, uriComponent } from '@oxog/vld';
stringToURL.parse('https://example.com/path?q=1');
stringToHttpURL.parse('https://api.example.com');
uriComponent.parse('Hello World!'); // "Hello%20World!"Binary Data Codecs
import { base64ToBytes, hexToBytes, utf8ToBytes, bytesToUtf8 } from '@oxog/vld';
base64ToBytes.parse('SGVsbG8='); // Uint8Array
hexToBytes.parse('48656c6c6f'); // Uint8Array
utf8ToBytes.parse('Hello'); // Uint8Array
bytesToUtf8.parse(new Uint8Array([72, 101, 108, 108, 111])); // "Hello"Custom Codecs
const csvToArray = v.codec(
v.string(),
v.array(v.string()),
{
decode: (csv: string) => csv.split(',').map(s => s.trim()),
encode: (arr: string[]) => arr.join(', ')
}
);
const tags = csvToArray.parse('react, typescript, vld');
// ["react", "typescript", "vld"]
const csvString = csvToArray.encode(['node', 'express', 'api']);
// "node, express, api"Plugin System
VLD v1.5.0 introduces a powerful plugin system for extending functionality.
Creating a Plugin
import { definePlugin, usePlugin, v } from '@oxog/vld';
// Define a custom plugin
const myPlugin = definePlugin({
name: 'my-plugin',
version: '1.0.0',
// Custom validators
validators: {
phoneNumber: () => v.string().regex(/^\+?[1-9]\d{1,14}$/),
postalCode: () => v.string().regex(/^\d{5}(-\d{4})?$/)
},
// Custom transforms
transforms: {
normalizePhone: (phone: string) => phone.replace(/[^\d+]/g, '')
},
// Lifecycle hooks
install(kernel) {
console.log('Plugin installed!');
}
});
// Register the plugin
usePlugin(myPlugin);Using Plugin Validators
import { createVldKernel, usePlugin } from '@oxog/vld';
const kernel = createVldKernel({ debug: true });
kernel.use(myPlugin);
// Access custom validators
const phoneSchema = kernel.validator('phoneNumber');
phoneSchema.parse('+1234567890');Result Pattern
VLD v1.5.0 includes a functional Result pattern for error handling.
Basic Usage
import { Ok, Err, match, map, flatMap, tryCatch } from '@oxog/vld';
// Create results
const success = Ok(42);
const failure = Err(new Error('Something went wrong'));
// Pattern matching
const message = match(success, {
ok: (value) => `Got: ${value}`,
err: (error) => `Error: ${error.message}`
});
// Transform results
const doubled = map(success, (n) => n * 2); // Ok(84)
// Chain operations
const result = flatMap(success, (n) =>
n > 0 ? Ok(n * 2) : Err(new Error('Must be positive'))
);
// Safe function execution
const parsed = tryCatch(() => JSON.parse('{"a":1}'));With Validation
import { v, isOk, isErr, unwrapOr } from '@oxog/vld';
const schema = v.object({
name: v.string(),
age: v.number().min(0)
});
const result = schema.safeParse(data);
if (isOk(result)) {
console.log('Valid:', result.data);
} else {
console.log('Invalid:', result.error);
}
// With default value
const user = unwrapOr(result, { name: 'Guest', age: 0 });Combining Results
import { all, fromNullable } from '@oxog/vld';
// Combine multiple results
const results = [Ok(1), Ok(2), Ok(3)];
const combined = all(results); // Ok([1, 2, 3])
// Convert nullable to Result
const maybeValue: string | null = getValue();
const result = fromNullable(maybeValue, new Error('Value is null'));CLI Tools
VLD includes command-line tools for validation and benchmarking.
Installation
npm install -g @oxog/vld
# or use npx
npx vld --helpCommands
# Show help
vld --help
# Validate data
vld validate schema.json data.json
# Run benchmarks
vld benchmark
# Show version
vld --versionProgrammatic CLI
import { createCli, vldCli } from '@oxog/vld/cli';
// Use the built-in CLI
vldCli.run(process.argv.slice(2));
// Or create a custom CLI
const cli = createCli('my-app', '1.0.0', 'My validation app')
.command({
name: 'validate',
description: 'Validate data',
action: async (args, options) => {
// Custom validation logic
}
});
cli.run(process.argv.slice(2));Logger & Colored Output
VLD includes a logging system and colored terminal output.
Logger
import { createLogger, setLogLevel, enableDebug } from '@oxog/vld';
// Create a logger
const logger = createLogger({ prefix: 'VLD' });
logger.info('Processing...');
logger.warn('Deprecated feature');
logger.error('Validation failed');
logger.debug('Debug info');
// Set log level globally
setLogLevel('debug');
// Enable debug mode
enableDebug();Colored Output (Pigment)
import { pigment, red, green, blue, bold, dim } from '@oxog/vld';
console.log(red('Error!'));
console.log(green('Success!'));
console.log(bold(blue('Important')));
console.log(dim('Less important'));
// Or use the pigment object
console.log(pigment.red('Error!'));
console.log(pigment.bold(pigment.green('Success!')));VLD vs. Zod
VLD is designed as a compelling alternative to Zod, offering full feature parity while delivering significant improvements.
Feature Comparison
| Feature | VLD | Zod |
| ----------------------- | ---------------------------------- | ------------------------------------ |
| Performance | Release-gated faster runtime, startup, and memory paths | Baseline |
| Memory Usage | ~4.85x less overall | Baseline |
| Internationalization| Built-in (27+ languages) | Requires third-party library |
| Dependencies | Zero | zod-i18n for locales |
| Bundle Size | Smaller | Larger |
| API | 100% Zod-compatible | Standard Zod API |
| Plugin System | Built-in | Not available |
| Result Pattern | Built-in | Not available |
| CLI Tools | Built-in | Not available |
| Codecs | Built-in, bidirectional | Built-in |
| Type Inference | Excellent | Excellent |
Seamless Migration from Zod
// Before (Zod)
import { z } from 'zod';
const schema = z.string().email();
// After (VLD) - Exact same syntax!
import { v } from '@oxog/vld';
const schema = v.string().email();Drop-in Package Subpaths
VLD also exposes Zod-compatible package subpaths so applications that import Zod 4 entry points can migrate by changing the package name:
// Before
import { z } from 'zod';
import * as core from 'zod/v4/core';
import * as mini from 'zod/v4-mini';
import * as locales from 'zod/v4/locales';
// After
import { z } from '@oxog/vld';
import * as core from '@oxog/vld/v4/core';
import * as mini from '@oxog/vld/v4-mini';
import * as locales from '@oxog/vld/v4/locales';Release checks enforce zero missing exports and zero typeof mismatches for zod/v4, zod/v4-mini, zod/v4/mini, zod/v4/core, and zod/v4/locales against the installed latest Zod.
Real App Drop-in Verification
npm run verify:drop-in creates two temporary TypeScript applications from the same fixture:
- One imports and runs against real
zod. - One imports and runs against the locally built
@oxog/vldpackage. - The fixture exercises root APIs,
v4,v4-mini,v4/core,v4/locales, parsing, error formatting, JSON Schema output, mini helpers, and core factories. - The normalized runtime outputs must match exactly.
Benchmarks
Performance Results
Median of 11 samples per case against Zod 4.4.3, the latest stable release at the time of measurement. The release gate also runs focused runtime, startup, memory, package, install, security, Zod parity, and real drop-in app checks before publishing.
| Test Case | VLD Median Performance | Improvement | |-----------|----------------|-------------| | Simple String | 719.2M ops/sec | 3.40x faster | | Email Validation | 22.1M ops/sec | 2.87x faster | | Top-level Email Format | 22.8M ops/sec | 3.66x faster | | StringBool Validation | 32.7M ops/sec | 3.44x faster | | Number Validation | 226.2M ops/sec | 27.62x faster | | Simple Object | 37.7M ops/sec | 1.40x faster | | Complex Object | 2.3M ops/sec | 1.02x faster | | Array Validation | 39.8M ops/sec | 6.74x faster | | Union Types | 38.1M ops/sec | 4.10x faster | | Optional Values | 236.9M ops/sec | 7.57x faster | | Nullable Values | 224.7M ops/sec | 10.71x faster | | Nullish Values | 228.4M ops/sec | 52.92x faster | | Default Values | 207.8M ops/sec | 9.71x faster | | Catch Values | 232.1M ops/sec | 46.58x faster | | SafeParse | 162.0M ops/sec | 1.80x faster | | Type Coercion | 204.5M ops/sec | 8.72x faster | | Enum Validation | 180.3M ops/sec | 1.32x faster | | Discriminated Union | 19.2M ops/sec | 1.79x faster | | Tuple Validation | 50.0M ops/sec | 7.99x faster | | Record Validation | 10.7M ops/sec | 5.63x faster | | Set Validation | 18.9M ops/sec | 1.84x faster | | Map Validation | 14.8M ops/sec | 2.37x faster | | BigInt Validation | 164.8M ops/sec | 14.88x faster | | Date Validation | 227.2M ops/sec | 2.57x faster | | Symbol Validation | 230.0M ops/sec | 1.01x faster | | Any Validation | 232.5M ops/sec | 1.01x faster | | Unknown Validation | 234.9M ops/sec | 1.04x faster | | Function Validation | 233.6M ops/sec | 3.52x faster | | Template Literal Validation | 39.3M ops/sec | 1.15x faster | | Promise Async Validation | 6.3M ops/sec | 1.38x faster |
VLD won 30/30 snapshot tests. Release checks additionally enforce runtime, startup, memory, Zod subpath parity, and real drop-in app guard thresholds against Zod.
Run Benchmarks
# Quick performance comparison
npm run benchmark
# Median-based stable comparison
npm run benchmark:stable
# Fast CI-friendly performance regression guard
npm run benchmark:guard
# Full release gate: lint, source and published types, tests, exports, package and install checks, security audit, Zod parity, real drop-in app verification, and performance guards
npm run release:check
# Memory usage comparison
npm run benchmark:memory
# Startup time comparison
npm run benchmark:startup
# Run all benchmarks
npm run benchmark:allContributing
Contributions are welcome! Please feel free to submit a Pull Request.
Links
Made with Love by Ersin KOC
