vld.
A LITTLE VALIDATION. A LOT OF POSSIBILITY.

Let’s build
with confidence.

A quick field guide to good data. Install VLD, describe your schema, and let TypeScript take it from there.

01 / Getting started

Install the package with your favorite package manager. VLD has zero third-party runtime dependencies.

$ npm install @oxog/vld

Define the shape of your data, then call safeParse. It returns a success result or structured validation issues without throwing.

getting-started.ts
import { v } from '@oxog/vld';const user = v.object({  name: v.string().min(2),  email: v.string().email(),  age: v.number().int().positive(),});type User = v.infer<typeof user>;const result = user.safeParse({  name: 'Alex Morgan',  email: 'alex@example.com',  age: 28,});if (result.success) {  console.log(result.data); // Typed as User} else {  console.log(result.error.issues);}
Run it in the playground

02 / Schema essentials

Start with primitives. Chain constraints. Compose them into objects and collections.

schemas.ts
v.string().min(2).max(100);v.string().email();v.number().int().positive();v.boolean();v.enum('admin', 'user', 'guest');v.array(v.string()).min(1);v.object({ name: v.string() });// Optional values, defaults, and transformationsv.string().optional();v.string().default('hello');v.string().transform(value => value.trim());v.coerce.number().parse('42'); // 42

Use parse when you want validation to throw, or safeParse when you want to handle the result explicitly.

03 / One schema. One source of truth.

Derive your TypeScript types directly from your schemas. When a schema changes, its inferred type changes with it.

types.ts
const profile = v.object({  username: v.string().min(3),  bio: v.string().optional(),});type Profile = v.infer<typeof profile>;// { username: string; bio?: string }

04 / Already using Zod?

VLD exposes the familiar z alias and compatible entry points. Change your import, then run your application’s checks against the new package.

migration.ts
// Beforeimport { z } from 'zod';// Afterimport { z } from '@oxog/vld';// Same familiar schemaconst user = z.object({  name: z.string().min(2),  email: z.string().email(),});
Opt into the V2 implementation

For the newer method-memoization implementation, use import { vV2 as v } from '@oxog/vld'. The V1 factory API remains the default.

Read the compatibility notes

05 / Take only what you need.

The Mini entry point exposes standalone functions for bundle-conscious applications.

mini.ts
import { object, string, number, optional }  from '@oxog/vld/mini';const user = object({  name: string().min(2),  age: optional(number().positive()),});

06 / Clarity in every language.

Built-in error localization supports 27+ languages. Use a locale directly, or load it on demand to keep your initial bundle light.

locales.ts
import { v, setLocale } from '@oxog/vld';setLocale('tr');const result = v.string().email().safeParse('oops');// Or load translations only when you need themimport { setLocaleAsync } from '@oxog/vld/locales/lazy';await setLocaleAsync('ja');

Ready for the deeper stuff?

Codecs, async refinements, plugins, result patterns, and the complete API live in the repository documentation.

Explore the complete reference