Back to home

How generation works

This page explains the mechanism behind MockLab's central claim — no record limit — openly enough that you can reason about its actual trade-offs, not just trust the marketing.

The seed

Every resource has a seed: a short random string assigned when the resource is created. The seed, together with a record's index (its position in the list — 0, 1, 2, and so on), is the only input generation ever needs. Given the same seed and the same index, the same field types, in the same order, always produce the same values — on any machine, in any process, without any record ever being written to a database first.

The mechanism

For record index i, the server computes a numeric hash of seed + ":" + i and uses it to seed a small, fast pseudo-random number generator. Every field in the schema then draws from that one generator, in the order the fields appear in the schema — which is exactly why reordering fields in the schema builder changes what each field produces (each field's draw from the sequence shifts), while adding an option to an existing field only changes that field's own output. A record's id is deliberately generated from a separate sequence, seeded from seed + ":id:" + i — independent of the data fields — specifically so that editing your schema's fields never changes the ids already handed out for existing records.

This is also why generating a million records costs almost nothing: there's no lookup, no database row, no stored state per record at all. The server does a small amount of arithmetic per record, per request, and only for the records in the page you actually asked for.

What actually gets stored

Nothing about the generated data is ever stored. The only thing persisted is your overrides — the result of every POST, PUT, PATCH, and DELETE you've made (see Creating, updating and deleting). A read request generates the requested window of records, merges any overrides on top (replacing edited records, dropping deleted ones, appending newly created ones), then filters, searches, sorts, and paginates the result.

The honest limit: 10,000 records

For resources with 10,000 records or fewer, the server materializes the whole merged dataset into memory once per data version and serves filtering, searching, and sorting from that. Above 10,000, filtering, searching, and sorting are disabled entirely — only pagination works. This isn't a marketing footnote: a response affected by it carries a real, checkable header, X-MockLab-Notice: sort-filter-disabled-above-10000, so your code (or you, reading the network tab) can tell it happened rather than silently getting unsorted or unfiltered results.

const response = await fetch("https://mocklab.dev/m/demo7k2m9x/logs?sort=createdAt");
if (response.headers.get("X-MockLab-Notice") === "sort-filter-disabled-above-10000") {
  console.warn("This resource is too large for sort/filter — showing unsorted pages instead.");
}
const records = await response.json();
import { useQuery } from "@tanstack/react-query";

function useSortedRecords(sort) {
  return useQuery({
    queryKey: ["logs", sort],
    queryFn: async () => {
      const res = await fetch(`https://mocklab.dev/m/demo7k2m9x/logs?sort=${sort}`);
      return {
        records: await res.json(),
        sortDisabled: res.headers.get("X-MockLab-Notice") === "sort-filter-disabled-above-10000",
      };
    },
  });
}

The same limit affects single-record routes above 10,000 records, in a related way: GET, PUT, PATCH, and DELETE by id only work for records that already carry an override, because turning an arbitrary id back into its generation index would mean generating records until one matches — exactly the unbounded scan the limit exists to prevent. Below 10,000 records, none of this applies; every record is addressable by id immediately, sorting and filtering are always available, and the notice header never appears. A future version raises this limit with a proper index; for now it's documented rather than hidden.