dhi
v1.7.0
Published
Ultra-fast Zod 4 drop-in replacement - 20x faster average, full API parity, SIMD WASM, 28KB binary
Maintainers
Readme
dhi
Drop-in Zod 4 replacement. Average 13.8x faster than Zod 4, with 1.3.1 URL and IPv4 hot paths 2.9x and 2.4x faster than before. Zero code changes.
- import { z } from 'zod';
+ import { z } from 'dhi';That's it. Same API. Same types. Full Zod 4 compatibility. Just faster.
Benchmarks
Performance Summary
| Category | Average Speedup | |----------|-----------------| | Full benchmark suite | 13.8x faster than Zod 4 | | URL validator | 30.17M/s — 8.0x vs Zod; 2.9x faster than pre-1.3.1 | | IPv4 validator | 22.28M/s — 1.1x vs Zod; 2.4x faster than pre-1.3.1 | | Number Formats | 30-50x faster | | StringBool | 32x faster | | Coercion | 23-56x faster | | String Formats | 12-27x faster | | ISO Formats | 12-22x faster | | Objects | 4-7x faster | | Arrays | 8x faster |
Release 1.3.1 benchmark command:
bun run benchmarks/benchmark-vs-all.ts. Pre-1.3.1 comparison used the previous release-branch commit before the TypeScript fast paths.
Install
npm install dhi
# or
bun add dhi
# or
pnpm add dhiQuick Start
import { z } from 'dhi';
const User = z.object({
id: z.string().uuid(),
name: z.string().min(2).max(100),
email: z.email(), // New Zod 4 top-level shortcut!
age: z.int().positive(), // New Zod 4 number format!
role: z.enum(['admin', 'user', 'guest']),
tags: z.array(z.string()).optional(),
createdAt: z.iso.datetime(), // New Zod 4 ISO namespace!
});
type User = z.infer<typeof User>;
const user = User.parse(data); // throws on invalid
const result = User.safeParse(data); // { success, data } or { success, error }Full Zod 4 Feature Parity
dhi implements 100% of the Zod 4 API, including all the new Zod 4 features:
Top-Level String Format Shortcuts (New in Zod 4)
z.email() // Email validation
z.uuid() // UUID validation
z.url() // URL validation
z.ipv4() // IPv4 address
z.ipv6() // IPv6 address
z.jwt() // JSON Web Token
z.nanoid() // NanoID
z.ulid() // ULID
z.cuid() // CUID
z.cuid2() // CUID2
z.base64() // Base64 string
z.base64url() // Base64URL string
z.e164() // E.164 phone number
z.mac() // MAC address
z.cidrv4() // CIDR v4 block
z.cidrv6() // CIDR v6 block
z.hex() // Hexadecimal string
z.hostname() // Hostname
z.hash('sha256') // Hash strings (md5, sha1, sha256, sha384, sha512)ISO Namespace (New in Zod 4)
z.iso.datetime() // ISO 8601 datetime
z.iso.date() // ISO 8601 date
z.iso.time() // ISO 8601 time
z.iso.duration() // ISO 8601 durationNumber Format Shortcuts (New in Zod 4)
z.int() // Safe integer
z.float() // Finite float
z.float32() // 32-bit float
z.float64() // 64-bit float
z.int8() // 8-bit signed integer (-128 to 127)
z.uint8() // 8-bit unsigned integer (0 to 255)
z.int16() // 16-bit signed integer
z.uint16() // 16-bit unsigned integer
z.int32() // 32-bit signed integer
z.uint32() // 32-bit unsigned integer
z.int64() // 64-bit signed integer (BigInt)
z.uint64() // 64-bit unsigned integer (BigInt)Additional Zod 4 Features
// StringBool - env-style boolean parsing
z.stringbool() // "true", "yes", "1", "on" → true
// "false", "no", "0", "off" → false
// Template Literals
z.templateLiteral(['user-', z.number()]) // Matches "user-123"
// JSON Schema
z.json() // Any JSON-encodable value (recursive)
// File Validation
z.file() // File object
z.file().mime('image/png')
z.file().min(1024).max(5_000_000)
// Registry System
const registry = z.registry<{ title: string }>();
registry.add(schema, { title: 'User Schema' });
z.globalRegistry.add(schema, { id: 'user', description: 'User data' });
// Success Wrapper
z.success(z.string()) // Always succeeds
// Pretty Error Formatting
z.prettifyError(error) // Formatted error stringObject Methods (New in Zod 4)
const schema = z.object({ name: z.string(), age: z.number() });
schema.keyof() // z.enum(['name', 'age'])
schema.valueof() // Union of all value schemas
schema.entryof() // Tuple entriesAll Classic Features
Primitives — string, number, bigint, boolean, date, symbol, undefined, null, void, never, any, unknown, nan
String Checks — min, max, length, email, url, uuid, regex, includes, startsWith, endsWith, trim, toLowerCase, toUpperCase, normalize
Number Checks — min, max, gt, gte, lt, lte, int, positive, negative, nonnegative, nonpositive, finite, safe, multipleOf
Composites — object, array, tuple, record, map, set, union, discriminatedUnion, intersection
Modifiers — optional, nullable, nullish, default, catch, readonly, brand
Effects — transform, refine, superRefine, check, preprocess, pipe
Coercion — z.coerce.string(), z.coerce.number(), z.coerce.boolean(), z.coerce.bigint(), z.coerce.date()
Why It's Fast
Three things working together:
JIT-compiled object schemas — When you define an object schema, dhi generates a specialized validator function for that exact shape. No loops, no dynamic dispatch. Just straight-line type checks.
Hand-written format scanners — Email, UUID, IPv4, base64 and ISO date validation are branch-light
charCodeloops instead of regexes, and their accept/reject behaviour is verified against Zod itself on thousands of inputs (tests/test-zod-parity.ts).Zero-allocation fast paths — Errors only allocate when validation actually fails. The happy path avoids the garbage collector entirely.
The z API is pure TypeScript: no WASM to instantiate, no top-level await, so
it loads instantly and bundles anywhere (the optional SIMD WASM module only
backs the low-level validators / dhi/turbo APIs).
Migration from Zod
One-line change
// Before
import { z } from 'zod';
// After
import { z } from 'dhi';Full type inference works
import { z } from 'dhi';
const PostSchema = z.object({
title: z.string(),
body: z.string().min(10),
published: z.boolean().default(false),
tags: z.array(z.string()),
});
type Post = z.infer<typeof PostSchema>;
// { title: string; body: string; published: boolean; tags: string[] }Same error handling
import { z, ZodError } from 'dhi';
try {
schema.parse(badData);
} catch (e) {
if (e instanceof ZodError) {
console.log(e.issues);
console.log(z.prettifyError(e)); // New! Pretty formatted errors
}
}Ecosystem compatibility
dhi schemas carry Zod 4's _zod internals and the Standard Schema (~standard)
interface, so libraries that detect a Zod 4 schema — and call Zod's own core
helpers on it — work unchanged. At the type level every dhi schema is
assignable to Zod's $ZodType, so z.output<S> / z.input<S> resolve to
dhi's inferred types.
import { z } from 'dhi';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
const server = new McpServer({ name: 'docs', version: '1.0.0' });
server.registerTool(
'search_docs',
{
description: 'Search the docs',
inputSchema: z.object({
project: z.string().min(1).max(120),
query: z.string().min(1).max(500),
limit: z.number().int().min(1).max(20).default(8),
}),
},
// project: string, query: string, limit: number — contextual typing just works
async ({ project, query, limit }) => ({ content: [{ type: 'text', text: `${project}:${query}:${limit}` }] }),
);| Integration | Status | Covered by |
|-------------|--------|------------|
| @modelcontextprotocol/sdk (registerTool, registerPrompt, raw shapes, output schemas) | ✅ | tests/test-mcp-compat.ts, tests/typecheck/ |
| Vercel AI SDK (generateObject, streamObject, tool schemas) | ✅ | tests/test-ai-sdk-compat.ts |
| Standard Schema v1 + Standard JSON Schema v1 | ✅ | tests/test-standard-schema-and-jsonschema.ts |
| Zod 4 core (z.safeParse(dhiSchema), z.toJSONSchema(dhiSchema), instanceof z.ZodObject) | ✅ | tests/test-zod-parity.ts |
| Next.js 16 (Turbopack + webpack), App Router, Edge Runtime | ✅ | dhi/nextjs — same core, no WASM / TLA |
| OpenNext + Cloudflare Workers | ✅ | dhi/cloudflare — same core |
| Deno / Bun / Node 18+ / browsers | ✅ | — |
Run Benchmarks
git clone https://github.com/justrach/dhi-zig.git
cd dhi-zig/js-bindings
bun install
bun run benchmark-vs-zod.ts # Full comparison
bun run benchmark-zod4-features.ts # Zod 4 featuresRequirements
- Node.js 18+ / Bun / Deno
- Works anywhere JavaScript runs (browsers, Workers, edge runtimes) — no WASM, no top-level await
Bundle Size
- Pure TypeScript core, zero production dependencies
- Optional 28KB WASM binary (gzipped: ~12KB) for the low-level
validators/dhi/turboAPIs
API Reference
See the Zod 4 documentation — dhi implements the same API with 100% compatibility.
License
MIT
dhi (धी, Sanskrit: wisdom, intelligence) — because validation shouldn't be the bottleneck.
