zod4-mock
v0.5.0
Published
Deterministic, schema-driven mock data generator for Zod v4
Downloads
1,097
Maintainers
Readme
zod4-mock
Deterministic, schema-driven mock data for Zod v4.
Same seed → same data, always. Field names like email, firstName, and createdAt automatically produce realistic values. Schemas can declare relations so IDs stay consistent across multiple API shapes — without any manual wiring.
Quick start
import { z } from "zod";
import { generate } from "zod4-mock";
const user = generate(
z.object({
id: z.uuid(),
firstName: z.string(),
email: z.email(),
role: z.enum(["admin", "user"]),
createdAt: z.date(),
}),
);
// → { id: "3f2d…", firstName: "Jan", email: "j.bakker@…", role: "user", createdAt: Date }No setup, no seed, no configuration. Field names drive the values — firstName gets a first name, email gets a valid email address, id gets a UUID.
Installation
npm install zod4-mock zod@^4Seeded worlds
For tests, pin a seed so every run produces identical data:
import { createWorld } from "zod4-mock";
const world = createWorld({ seed: 42 });
const users = world.generate(z.array(UserSchema).min(5).max(20));
// Byte-identical output every run, every machineCustom field values
Register matchers to control specific fields. ctx.gen gives you the full generator library with the PRNG already applied — no need to pass prng anywhere:
const world = createWorld({ seed: 42 }).withSchema(ProductSchema, {
matchers: {
name: (ctx) => ctx.gen.commerce.productName(),
sku: (ctx) => `SKU-${ctx.gen.string.alphanumeric(6)}`,
price: (ctx) => ctx.prng.int(100, 50_000), // cents, custom range
},
});
const products = world.generate(z.array(ProductSchema).min(10));Any field without a matcher falls through automatically: key-name heuristics first, then Zod type introspection.
Related schemas
Declare relations between schemas to keep foreign keys coherent across different API shapes:
const world = createWorld({ seed: 42 })
.withSchema(PersonSchema)
.withSchema(DocumentSchema, {
relations: { author: PersonSchema },
matchers: {
authorId: (ctx) => ctx.related("author").personId,
title: (ctx) => ctx.gen.word.sentence(),
},
});
const people = world.generate(z.array(PersonSchema).min(3));
const documents = world.generate(z.array(DocumentSchema).min(10));
// documents[*].authorId ∈ people[*].personId — guaranteedDerived schemas
When two API shapes represent the same underlying entity, bind the second to the first with from. The source entity's data is available as ctx.source:
const world = createWorld({ seed: 42 })
.withSchema(PersonSchema)
.withSchema(PersonSummarySchema, {
from: PersonSchema,
matchers: {
id: (ctx) => ctx.source.personId,
displayName: (ctx) => `${ctx.source.firstName} ${ctx.source.lastName}`,
initials: (ctx) => `${ctx.source.firstName[0]}${ctx.source.lastName[0]}`,
},
});
const people = world.generate(z.array(PersonSchema).min(5));
const summaries = world.generate(z.array(PersonSummarySchema));
// people[0].personId === summaries[0].id — alwaysNested schemas compose
Register matchers for a schema once — they apply automatically wherever that schema appears, including nested inside other schemas:
const world = createWorld({ seed: 42 })
.withSchema(AddressSchema, {
matchers: {
street: (ctx) => ctx.gen.location.street(),
city: (ctx) => ctx.gen.location.city(),
country: (ctx) => ctx.gen.location.countryCode(),
},
})
.withSchema(PersonSchema); // has address: AddressSchema
// PersonSchema's address field uses AddressSchema's matchers automatically
const person = world.generate(PersonSchema);Features
- Zero-config —
generate(schema)works with no setup, no imports beyond the schema - Deterministic — same seed → identical output on every run and every machine
- Field-name heuristics —
email,firstName,createdAt,userId,street,iban,vin, and 150+ more auto-generate realistic values - Schema-driven — respects
.min(),.max(),.email(),.uuid(),z.enum(),z.union(),z.optional(),z.discriminatedUnion(), and more - Composable — nested schemas automatically use their registered matchers
- Relational — cross-schema ID consistency without any manual wiring
ctx.gen— full generator library (person, internet, location, finance, commerce, …) pre-wired to the PRNG inside matchers- Per-field seeding — adding or removing schema fields never disturbs values of other fields
- Zod v4 native — built against
zod@^4
Documentation
- Getting Started — step-by-step tutorial
- Concepts — world, schemas, relations, registry, determinism
- API Reference — complete reference for all exports
- Key-Based Field Heuristics — auto-generated values by field name
- Recipes — copy-pasteable patterns for common scenarios
License
MIT
