mockingpug

Performance

Where the cost actually is, and what mockingpug does about it

The main risks are large amounts (thousands to hundreds of thousands of records), cross-entity references (potentially O(n·m) with a naive implementation), and file I/O inside Next.js's serverless-style runtime, where blocking the event loop hurts every concurrent request, not just one.

Generation is a pure, per-record function

Every field's value depends only on (seed, entity, index, fieldName), never on other fields or on previously generated records. This is why reconciliation (see Reconciliation & Storage) can regenerate a single changed field across every existing record without touching anything else, and why number.increment correctly continues past the existing max when more records are appended, rather than restarting.

Cross-references don't materialize whole entities

A field-level reference (data.user.id) only needs a cheap array of already-generated id values from the target entity, not full copies of every target record. A bare relation (data.blogpost, see Relations & Generation Order) is computed as a lazy join at read time and is never persisted alongside the "owning" record, so an N-to-M relationship doesn't grow storage quadratically.

Reconciliation avoids unnecessary work

An entity's schema fingerprint (a stable hash of its data block) is compared cheaply before deciding anything needs to happen. An unchanged entity is skipped without re-reading or re-hashing its stored records. Only the specific fields/records a schema change actually touches get regenerated.

Route matching

Both transports build their request handlers once, at startup. createMockHandlers() for mockingpug/react produces an array of MSW handlers up front (matched internally by MSW's own matcher, not re-evaluated by mockingpug per request); mockingpug/next's catch-all resolves an entity via a plain object property lookup (schemas[entityName]), not a linear scan. At the route counts a real project has (tens to low hundreds of entities), this is effectively O(1) without needing a dedicated routing data structure.

Known limitation: full materialization

The generator currently materializes an entity's entire amount on any run that needs to touch it. It does not (yet) generate only the specific page of records a GET ?page=3&limit=20 actually asked for. For the typical range this library targets (low thousands of records per entity) this is not noticeable. If you're pushing amount toward the upper end of what limits.maxAmount allows, be aware that a schema change touching that entity regenerates however many records the reconciliation plan requires, in memory, before persisting. This is a known, intentionally deferred piece of future work, not an oversight: limits.maxAmount exists partly to keep this from becoming a real problem in practice today.

File I/O and serverless

persist.adapter: 'file' writes are synchronous today. On a platform without a persistent filesystem between invocations (most serverless hosts), those writes simply won't survive the next cold start. Use persist.adapter: 'memory' there if you don't need mutations to persist across requests. There is no automatic serverless-environment detection (e.g. auto-switching based on process.env.VERCEL) yet; this is a documented limitation, not silent data loss. See the Next.js guide's known limitations.

Bundle size (React/browser)

Nothing generator- or MSW-related should reach a production bundle at all. See Security → keeping the mock layer out of production for the dead-code-elimination pattern this depends on. Within the dev-only mock bundle itself, uuid/hash generators are implemented on the same seeded RNG as everything else (not node:crypto or the async Web Crypto API), which keeps them synchronous and dependency-free in a browser context (a deliberate tradeoff, since mock hashes/UUIDs never need to be cryptographically real).

On this page