TypeScript-first schema validation library with static type inference. Define schemas, validate data, and get type safety with zero dependencies.
Global configuration, utility functions, type utilities, regex patterns, registries, and helper functions for advanced Zod usage.
Global configuration for Zod behavior and error handling.
/**
* Configure global Zod settings
* @param options - Configuration options
*/
function config(options?: ConfigOptions): void;
interface ConfigOptions {
customError?: ZodErrorMap;
localeError?: ZodErrorMap;
jitless?: boolean;
}
type ZodErrorMap = (
issue: ZodIssueOptionalMessage,
ctx: ErrorMapCtx
) => { message: string };Usage Examples:
import * as z from 'zod';
// Set custom error map
z.config({
customError: (issue, ctx) => {
return { message: `Custom: ${ctx.defaultError}` };
},
});
// Set locale error map
z.config({
localeError: z.locales.es(),
});
// Disable JIT compilation for debugging
z.config({
jitless: true,
});
// Combine options
z.config({
localeError: z.locales.fr(),
jitless: false,
});Creates a deep copy of a schema.
/**
* Clone a schema
* @param schema - Schema to clone
* @returns Cloned schema
*/
function clone<T extends ZodTypeAny>(schema: T): T;Usage Examples:
import * as z from 'zod';
const OriginalSchema = z.object({
name: z.string(),
age: z.number(),
});
const ClonedSchema = z.clone(OriginalSchema);
// Modify cloned schema without affecting original
const ExtendedSchema = ClonedSchema.extend({
email: z.string().email(),
});
// Original remains unchanged
type Original = z.infer<typeof OriginalSchema>;
// { name: string; age: number }
type Extended = z.infer<typeof ExtendedSchema>;
// { name: string; age: number; email: string }Adds a description to a schema for documentation purposes.
/**
* Add a description to a schema
* @param description - Description text
* @returns Function that adds description to a schema
*/
function describe(description: string): (schema: ZodType) => ZodType;Usage Examples:
import * as z from 'zod';
// Add description to schema
const EmailSchema = z.describe('User email address')(z.string().email());
// Description can be accessed from schema
// Useful for generating documentation or JSON schemas
// Using with object properties
const UserSchema = z.object({
name: z.describe('Full name of the user')(z.string()),
email: z.describe('User email address')(z.string().email()),
age: z.describe('User age in years')(z.number().int().positive()),
});
// Can also use method syntax
const AgeSchema = z.number().describe('User age in years');Adds custom metadata to a schema for application-specific purposes.
/**
* Add custom metadata to a schema
* @param metadata - Custom metadata object
* @returns Function that adds metadata to a schema
*/
function meta<T = any>(metadata: T): (schema: ZodType) => ZodType;Usage Examples:
import * as z from 'zod';
// Add custom metadata
const ProductIdSchema = z.meta({ dbField: 'product_id', indexed: true })(
z.string().uuid()
);
// Metadata can be accessed for custom processing
const UserSchema = z.object({
id: z.meta({ primary: true })(z.string().uuid()),
name: z.meta({ searchable: true })(z.string()),
email: z.meta({ unique: true, indexed: true })(z.string().email()),
role: z.meta({ enum: 'user_role' })(z.enum(['admin', 'user', 'guest'])),
});
// Can also use method syntax
const TagSchema = z.string().meta({ category: 'taxonomy' });TypeScript utility types for extracting types from schemas.
/**
* Extract output type from schema
*/
type infer<T extends ZodType<any, any>> = T['_output'];
/**
* Extract output type (alias for infer)
*/
type output<T extends ZodType<any, any>> = T['_output'];
/**
* Extract input type from schema
*/
type input<T extends ZodType<any, any>> = T['_input'];Usage Examples:
import * as z from 'zod';
const UserSchema = z.object({
name: z.string(),
age: z.number(),
email: z.string().email(),
});
// Extract output type
type User = z.infer<typeof UserSchema>;
// { name: string; age: number; email: string }
// Alternative syntax
type UserOutput = z.output<typeof UserSchema>;
// Extract input type (useful with transformations)
const TransformSchema = z.string().transform((s) => parseInt(s, 10));
type Input = z.input<typeof TransformSchema>; // string
type Output = z.output<typeof TransformSchema>; // number
// Complex example
const FormSchema = z.object({
name: z.string().trim().toLowerCase(),
age: z.coerce.number(),
});
type FormInput = z.input<typeof FormSchema>;
// { name: string; age: unknown }
type FormOutput = z.output<typeof FormSchema>;
// { name: string; age: number }Type brand symbols for advanced type manipulations.
/**
* Symbol for output type metadata
*/
const $output: unique symbol;
/**
* Symbol for input type metadata
*/
const $input: unique symbol;
/**
* Symbol for branded types
*/
const $brand: unique symbol;Usage Examples:
import * as z from 'zod';
// Brand symbol usage
const UserId = z.string().brand<'UserId'>();
type UserId = z.infer<typeof UserId>;
// string & { [z.$brand]: "UserId" }
// Accessing type symbols (advanced usage)
type SchemaOutput<T> = T extends { [z.$output]: infer O } ? O : never;
type SchemaInput<T> = T extends { [z.$input]: infer I } ? I : never;Constant values used throughout Zod.
/**
* Never constant with type never
*/
const NEVER: never;
/**
* Time precision constants
*/
const TimePrecision: {
millisecond: 3;
second: 0;
};Usage Examples:
import * as z from 'zod';
// Use in exhaustiveness checking
function handleValue(value: 'a' | 'b') {
if (value === 'a') return 'handled a';
if (value === 'b') return 'handled b';
return z.NEVER; // Ensures all cases are handled
}
// Time precision for datetime validation
const PreciseDateTime = z.iso.datetime({
precision: z.TimePrecision.millisecond,
});Global schema registry for storing metadata with schemas.
/**
* Global schema registry
*/
const globalRegistry: {
add<T extends ZodTypeAny>(schema: T, metadata: any): void;
get<T extends ZodTypeAny>(schema: T): any | undefined;
has<T extends ZodTypeAny>(schema: T): boolean;
remove<T extends ZodTypeAny>(schema: T): void;
clear(): void;
};Usage Examples:
import * as z from 'zod';
const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
});
// Add metadata to schema
z.globalRegistry.add(UserSchema, {
tableName: 'users',
primaryKey: 'id',
version: 1,
});
// Retrieve metadata
const metadata = z.globalRegistry.get(UserSchema);
console.log(metadata.tableName); // "users"
// Check if schema has metadata
if (z.globalRegistry.has(UserSchema)) {
console.log('Schema is registered');
}
// Remove metadata
z.globalRegistry.remove(UserSchema);
// Clear all metadata
z.globalRegistry.clear();Create custom registries with typed metadata.
/**
* Create a custom registry
* @returns Registry with typed metadata
*/
function registry<Meta = any, Schema extends ZodTypeAny = ZodTypeAny>(): Registry<Meta, Schema>;
interface Registry<Meta, Schema extends ZodTypeAny> {
add(schema: Schema, metadata: Meta): void;
get(schema: Schema): Meta | undefined;
has(schema: Schema): boolean;
remove(schema: Schema): void;
clear(): void;
}Usage Examples:
import * as z from 'zod';
// Create typed registry
interface SchemaMetadata {
tableName: string;
version: number;
description?: string;
}
const schemaRegistry = z.registry<SchemaMetadata>();
const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
});
// Add with typed metadata
schemaRegistry.add(UserSchema, {
tableName: 'users',
version: 1,
description: 'User account schema',
});
// Get typed metadata
const meta = schemaRegistry.get(UserSchema);
if (meta) {
console.log(meta.tableName); // TypeScript knows this exists
}
// Multiple registries for different purposes
const validationRegistry = z.registry<{ validationLevel: 'strict' | 'loose' }>();
const documentationRegistry = z.registry<{ docs: string; examples: string[] }>();Built-in regex patterns for common validations.
/**
* Built-in regex patterns namespace
*/
namespace regexes {
// ID patterns
const cuid: RegExp;
const cuid2: RegExp;
const ulid: RegExp;
const xid: RegExp;
const ksuid: RegExp;
const nanoid: RegExp;
const guid: RegExp;
const uuid4: RegExp;
const uuid6: RegExp;
const uuid7: RegExp;
function uuid(version?: 4 | 6 | 7): RegExp;
// Email patterns
const email: RegExp;
const html5Email: RegExp;
const rfc5322Email: RegExp;
const unicodeEmail: RegExp;
const browserEmail: RegExp;
// Network patterns
const ipv4: RegExp;
const ipv6: RegExp;
function mac(delimiter?: string): RegExp;
const cidrv4: RegExp;
const cidrv6: RegExp;
// Encoding patterns
const base64: RegExp;
const base64url: RegExp;
const hex: RegExp;
// Domain patterns
const hostname: RegExp;
const domain: RegExp;
// Phone patterns
const e164: RegExp;
// Date/time patterns
const date: RegExp;
function time(args: TimeArgs): RegExp;
function datetime(args: DateTimeArgs): RegExp;
const duration: RegExp;
// Case patterns
const lowercase: RegExp;
const uppercase: RegExp;
// Hash patterns (examples, many more available)
const md5_hex: RegExp;
const md5_base64: RegExp;
const sha1_hex: RegExp;
const sha256_hex: RegExp;
const sha256_base64: RegExp;
const sha384_hex: RegExp;
const sha512_hex: RegExp;
}
interface TimeArgs {
precision?: number;
}
interface DateTimeArgs {
precision?: number;
offset?: boolean;
local?: boolean;
}Usage Examples:
import * as z from 'zod';
// Use built-in patterns directly
const EmailPattern = z.regexes.email;
const isValidEmail = EmailPattern.test('user@example.com'); // true
// UUID validation
const UuidPattern = z.regexes.uuid4;
const isValidUuid = UuidPattern.test('550e8400-e29b-41d4-a716-446655440000');
// Custom validation using patterns
const CustomEmail = z.string().regex(z.regexes.email, 'Invalid email');
// MAC address with custom delimiter
const macWithColon = z.regexes.mac(':');
const macWithDash = z.regexes.mac('-');
// Dynamic datetime pattern
const datetimePattern = z.regexes.datetime({
precision: 3,
offset: true,
});
// IP validation
const IpSchema = z.string().regex(
new RegExp(`^(${z.regexes.ipv4.source}|${z.regexes.ipv6.source})$`)
);
// Hash validation
const Sha256Schema = z.string().regex(z.regexes.sha256_hex);Helper functions and type utilities.
/**
* Utility namespace with helper functions
*/
namespace util {
// Object utilities
function isObject(value: unknown): value is object;
function isPlainObject(value: unknown): value is Record<string, unknown>;
function clone<T>(value: T): T;
function shallowClone<T>(value: T): T;
function objectClone<T extends object>(value: T): T;
// Type utilities
function getParsedType(data: unknown): ZodParsedType;
// Other utilities
function defineLazy(): any;
function captureStackTrace(): any;
function jsonStringifyReplacer(): (key: string, value: any) => any;
// Type definitions
type JSONType = string | number | boolean | null | JSONObject | JSONArray;
interface JSONObject { [key: string]: JSONType }
interface JSONArray extends Array<JSONType> {}
type Primitive = string | number | boolean | null | undefined | symbol | bigint;
type SafeParseSuccess<Output> = { success: true; data: Output };
type SafeParseError<Input> = { success: false; error: ZodError<Input> };
type SafeParseReturnType<Input, Output> =
| SafeParseSuccess<Output>
| SafeParseError<Input>;
type Flatten<T> = { [K in keyof T]: T[K] };
type Prettify<T> = { [K in keyof T]: T[K] } & {};
type NoNever<T> = { [K in keyof T as T[K] extends never ? never : K]: T[K] };
type Writeable<T> = { -readonly [K in keyof T]: T[K] };
type MakeReadonly<T> = { readonly [K in keyof T]: T[K] };
type MakePartial<T> = { [K in keyof T]?: T[K] };
type HasSize = { size: number };
type HasLength = { length: number };
type Numeric = number | bigint;
}Usage Examples:
import * as z from 'zod';
// Check if value is object
if (z.util.isObject(value)) {
console.log('Is an object');
}
// Check if plain object (not array, date, etc.)
if (z.util.isPlainObject(value)) {
console.log('Is a plain object');
}
// Clone values
const cloned = z.util.clone(complexObject);
const shallowCloned = z.util.shallowClone(simpleObject);
// Get parsed type
const type = z.util.getParsedType(value);
console.log(type); // "string", "number", "object", etc.
// JSON replacer for circular references
const json = JSON.stringify(obj, z.util.jsonStringifyReplacer());
// Type utilities
type User = { name: string; age: number };
type PrettyUser = z.util.Prettify<User>;
type PartialUser = z.util.MakePartial<User>;
type ReadonlyUser = z.util.MakeReadonly<User>;Combining configuration and utilities for advanced scenarios:
import * as z from 'zod';
// 1. Custom error handling with registry
const errorRegistry = z.registry<{ errorCode: string; severity: 'error' | 'warning' }>();
const CriticalSchema = z.string().min(1);
errorRegistry.add(CriticalSchema, { errorCode: 'CRITICAL_001', severity: 'error' });
function validateWithRegistry<T extends z.ZodTypeAny>(schema: T, data: unknown) {
const result = schema.safeParse(data);
if (!result.success) {
const meta = errorRegistry.get(schema);
return {
success: false,
error: result.error,
errorCode: meta?.errorCode,
severity: meta?.severity,
};
}
return { success: true, data: result.data };
}
// 2. Schema versioning with registry
const versionRegistry = z.registry<{ version: number; migrateFrom?: (data: any) => any }>();
const UserSchemaV1 = z.object({ name: z.string() });
const UserSchemaV2 = z.object({ name: z.string(), email: z.string() });
versionRegistry.add(UserSchemaV1, { version: 1 });
versionRegistry.add(UserSchemaV2, {
version: 2,
migrateFrom: (data) => ({ ...data, email: '' }),
});
// 3. Performance monitoring
const performanceRegistry = z.registry<{ avgParseTime: number; parseCount: number }>();
function monitoredParse<T extends z.ZodTypeAny>(schema: T, data: unknown) {
const start = performance.now();
const result = schema.safeParse(data);
const duration = performance.now() - start;
const meta = performanceRegistry.get(schema) || { avgParseTime: 0, parseCount: 0 };
const newCount = meta.parseCount + 1;
const newAvg = (meta.avgParseTime * meta.parseCount + duration) / newCount;
performanceRegistry.add(schema, {
avgParseTime: newAvg,
parseCount: newCount,
});
return result;
}interface ConfigOptions {
customError?: ZodErrorMap;
localeError?: ZodErrorMap;
jitless?: boolean;
}
type infer<T extends ZodType<any, any>> = T['_output'];
type output<T extends ZodType<any, any>> = T['_output'];
type input<T extends ZodType<any, any>> = T['_input'];
const $output: unique symbol;
const $input: unique symbol;
const $brand: unique symbol;
const NEVER: never;
const TimePrecision: {
millisecond: 3;
second: 0;
};
interface Registry<Meta, Schema extends ZodTypeAny> {
add(schema: Schema, metadata: Meta): void;
get(schema: Schema): Meta | undefined;
has(schema: Schema): boolean;
remove(schema: Schema): void;
clear(): void;
}
type ZodErrorMap = (
issue: ZodIssueOptionalMessage,
ctx: ErrorMapCtx
) => { message: string };
interface ErrorMapCtx {
defaultError: string;
data: any;
}Install with Tessl CLI
npx tessl i tessl/npm-zoddocs
guides
reference