Skip to content
v3.0.11 — true Zod 4.6 drop-in3.03× faster

Keep everything else.

VLD is a zero-dependency TypeScript validator that is 3.03× faster than Zod 4.6.4 on the honest head-to-head, using 4.7× less memory, and covering all 259 Zod 4.6 exports. Your schemas, your error shapes and your inferred types stay exactly where they are — you change one line.

import { z } from "zod"import { z } from "@oxog/vld"
$ npm install @oxog/vld
vld · live enginewarming

payloads

locale

userSchema.safeParse(payload) 0 issues
  • namestring().min(2).max(100)
  • emailstring().email()
  • agenumber().int().positive().optional()
  • roleenum(admin,user,guest).default()
  • tagsarray(string()).min(1)

result

{ … }

Every value above comes from @oxog/vld@… running in this tab. The ops/sec figure is this five-field strict schema measured on your machine for 250,000 parses, so it reflects your hardware rather than the published benchmark.

zero dependencies
drop-in for zod
full static inference
tree-shakeable
259/259 exports parity
zoderror shaped
32 locales
10/10 head-to-head wins
no runtime bloat
release-gated speed
The migration

One line changes.
Nothing else does.

VLD mirrors Zod's export structure, error shape and type inference. Point the import at @oxog/vld and your existing schemas, tests and form libraries keep working — just faster.

  • Identical inferred types — z.infer and v.infer resolve the same shapes.
  • ZodError-shaped failures via toZodError(), with .format() and .flatten().
  • Same subpaths: root, /v4, /v4-mini, /v4/core and /v4/locales.

3.03×

throughput

4.7×

less memory

10/10

scenario wins

259

exports matched

source: @oxog/vld
1// user.schema.ts2import { z } from "@oxog/vld";3 4export const userSchema = z.object({5  name: z.string().min(2).max(100),6  email: z.string().email(),7  age: z.number().int().positive().optional(),8  role: z.enum("admin", "user", "guest").default("user"),9});10 11export type User = z.infer<typeof userSchema>;12 13const result = userSchema.safeParse(input);14if (!result.success) console.log(result.error.issues);

3.03× faster · same errors · same types

The speed lab

The numbers are measured,
not marketing.

Every figure below is gated in CI on each commit against the latest stable Zod. Ten scenarios, one million safeParse operations, twenty-one runs, semantic-checked output.

0.00×geomean
VLD v3.0.11Zod 4.6.4 · 1.00×

0M

ops/sec · simple string

0.0×

less memory · V2

0

tests passing

0

built-in locales

higher is better

Simple string3× faster
VLD620M ops/s
Zod 4.6.4206.7M ops/s
Number / positive int9.1× faster
VLD253M ops/s
Zod 4.6.427.8M ops/s
Nullish parse30.7× faster
VLD214M ops/s
Zod 4.6.47.0M ops/s
Optional parse3.8× faster
VLD213M ops/s
Zod 4.6.456.1M ops/s
Array / object parse1.7× faster
VLD49M ops/s
Zod 4.6.428.8M ops/s
Union parse3.3× faster
VLD39M ops/s
Zod 4.6.411.8M ops/s
Discriminated union4.1× faster
VLD35M ops/s
Zod 4.6.48.5M ops/s

Want to reproduce it? The full harness ships in the repository — or run the head-to-head in your own browser.

Run the benchmark
Why it is fast and what else you get

Built for the hot path,
finished enough to ship.

Performance is the headline, but it would be useless on its own. VLD carries the ergonomics, the compatibility and the tooling you actually need in production.

release-gated

3.03× drop-in throughput

Only the import line changes. Same schemas, same error shapes, same TypeScript types — with a release-gated geometric mean of 3.03× over Zod 4.6.4, winning all ten scenarios.

opt-in

V2 method memoization

One __def object per instance, constraints as shared class instances, no bound function per method. 1.6–10× less memory per schema.

0 deps

Zero dependencies

Pure TypeScript with an empty dependency tree. Verified exports, installability and declaration files on every release.

types

Full static inference

v.infer<typeof schema> gives you the exact output type. No casts, no drift between schema and type.

compat

ZodError-shaped errors

toZodError() hands downstream tooling a real ZodError shape with .format() and .flatten() — plus prettifyError and treeifyError for humans.

i18n

32 built-in locales

Turkish, German, Japanese, Arabic, Hindi and 27 more — shipped in the box, or lazily loaded per locale for zero bundle cost.

parity

259/259 Zod 4.6 exports

.validate(), z.iban(), z.instanceof().properties(), z.withParser(), the 4.6 regex namespace — parity is verified per release.

mini

Tree-shakeable mini API

@oxog/vld/mini exports bare standalone functions with no class overhead, for bundle-constrained edge runtimes.

codecs

19 bidirectional codecs

Encode and decode with one object: string ↔ number, JSON, base64 ↔ bytes, hex and more.

result

Result pattern, no exceptions

Ok, Err, match, map, flatMap, tryCatch and unwrapOr give you functional error handling without a try/catch in sight.

Internationalization

32 languages,
already in the box.

No i18n plugin, no message catalogue to wire up. Call setLocale() and every issue comes back in the visitor's language — or load locales lazily so you only ship the ones you use.

enString must be at least 8 characters
trMetin en az 8 karakter olmalı
deString muss mindestens 8 Zeichen lang sein
ja文字列は8文字以上である必要があります

↑ produced by @oxog/vld during this page's build, not typed by hand.

32 locales registered
entresfrdeitptrujakozharhinlpldasvnofithviidbnguknneskswaftgpt-BRes-MX

lazy loading — only what you use

import { setLocaleAsync } from "@oxog/vld/locales/lazy";

await setLocaleAsync("tr");
// ships one locale, not thirty-two
enString must be at least 8 characters
trMetin en az 8 karakter olmalı
esLa cadena debe tener al menos 8 caracteres
frLa chaîne doit contenir au moins 8 caractères
deString muss mindestens 8 Zeichen lang sein
itLa stringa deve avere almeno 8 caratteri
ptString deve ter pelo menos 8 caracteres
ruСтрока должна содержать не менее 8 символов
ja文字列は8文字以上である必要があります
ko문자열은 최소 8자여야 합니다
zh字符串必须至少8个字符
arيجب أن يحتوي النص على 8 حرف على الأقل
hiस्ट्रिंग में कम से कम 8 अक्षर होने चाहिए
nlString moet ten minste 8 tekens lang zijn
plCiąg znaków musi mieć co najmniej 8 znaków
daStreng skal være mindst 8 tegn lang
svSträng måste vara minst 8 tecken lång
noStreng må være minst 8 tegn lang
fiMerkkijonon tulee olla vähintään 8 merkkiä pitkä
thข้อความต้องมีความยาวอย่างน้อย 8 ตัวอักษร
viChuỗi phải có ít nhất 8 ký tự
idString harus memiliki minimal 8 karakter
bnস্ট্রিং কমপক্ষে 8 অক্ষরের হতে হবে
guસ્ટ્રિંગ ઓછામાં ઓછા 8 અક્ષરોની હોવી જોઈએ
knಸ್ಟ್ರಿಂಗ್ ಕನಿಷ್ಠ 8 ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರಬೇಕು
neस्ट्रिङ कम्तीमा 8 अक्षरहरूको हुनुपर्छ
skReťazec musí mať aspoň 8 znakov
swMfuatano lazima uwe na angalau vibambo 8
afString moet ten minste 8 karakters lank wees
tgСатр бояд ҳадди ақал 8 аломат дошта бошад
pt-BRString deve ter pelo menos 8 caracteres
es-MXLa cadena debe tener al menos 8 caracteres
API surface

Everything Zod 4.6 has.
Plus the parts it skipped.

259 of 259 public Zod 4.6 exports are covered and verified per release — including .validate(), z.iban(), z.instanceof().properties() and z.withParser().

Chainable validators with full static inference — the shape you write is the shape you get.

schema.tstypescript
1import { v } from "@oxog/vld";2 3const userSchema = v.object({4  name: v.string().min(2).max(100),5  email: v.string().email(),6  age: v.number().int().positive().optional(),7  role: v.enum("admin", "user", "guest").default("user"),8  tags: v.array(v.string()).min(1),9});10 11type User = v.infer<typeof userSchema>;12 13const result = userSchema.safeParse(input);14 15if (result.success) {16  console.log(result.data); // typed as User, no casts17}
live in your browser

Stop reading claims.
Run the engine.

The playground loads the real published package into your tab. Build a schema, watch it validate, switch locale, flip V2 mode on and off, and read the throughput your own machine reports.

vld · engine

$ vld run ./schema.ts

→ schema compiled

→ 10/10 scenarios · 3.03x geomean

→ 0 issues · 0 dependencies

$