Core Concepts
storymock has three layers. Each builds on the one below:
┌─────────────────────────────────────────┐
│ Story — Composes schemas, wires refs │
├─────────────────────────────────────────┤
│ Schema — Maps fields → fakers → objects│
├─────────────────────────────────────────┤
│ Faker — Generates a single value │
└─────────────────────────────────────────┘You can use any layer on its own — a faker works without a schema, a schema works without a story. Each layer adds structure and relationships on top of the one below.
Faker
A faker is an immutable, lazy builder that describes how to generate a value. No value is produced until .create() is called, and every method call returns a new instance.
numeric().min(18).max(65).create(); // 34Schema
A schema is a typed factory for mock objects. Each field maps to a faker, literal, when(), or derive(), with compile-time type checking via the generic parameter.
const UserSchema = schema<User>({ id: text().uuid(), name: person().fullName(), age: person().age().min(18) });Story
A story composes multiple schemas into a referentially-linked dataset. Use ref() for foreign keys and .setup() for complex wiring.
const checkout = story().add('user', UserSchema).add('order', OrderSchema, { userId: ref('user') }).create();Domains
Domains are entry points for creating fakers. Core domains (numeric(), text(), temporal(), bool(), choice(), collection()) are structural building blocks. Semantic domains (person(), internet(), finance(), etc.) produce real-world data and return core fakers, so constraints keep chaining: person().age().min(18), internet().email().not('a@b'). → Faker API Reference
Mixins
Mixins grant capabilities to fakers. Not every mixin applies to every domain.
| Mixin | Methods | Applies to |
|---|---|---|
| Bounded | .min(), .max(), .between() | numeric, temporal |
| Measurable | .length(), .minLength(), .maxLength() | text, collection |
| Excludable | .not() | numeric, text, temporal, choice |
| Nullable | .nullable(), .optional() | all fakers |
| Seedable | .seed(n) | all fakers |
Traits
A trait is a named set of field overrides representing a specific state ("admin", "expired"). Traits are partial and type-checked — you only override the fields you need.
UserSchema.trait('admin', { role: 'admin' as const }).with('admin').create();Immutability
Every method on every layer returns a new instance — the original is never modified. This makes fakers, schemas, and stories safe to fork, store, and compose without side effects.
const base = numeric().min(0).max(100);
const small = base.max(10); // new instance — base is unchanged