Random test data breaks tests. Seeded test data does not.
A snapshot test built on fresh random data fails on a schedule nobody chose. One run the price lands on 42.50, the next run it comes back 42.5 after JSON encoding drops the trailing zero, and the assertion falls over at 3am on a branch that changed nothing. The answer is not less randomness. The answer is randomness you reproduce on demand.
Type anything into the seed box. The generator hashes that string into a starting state for a small deterministic pseudo random function, then draws every value from it in order. Feed it invoice-tests and you get one dataset. Feed it invoice-tests-2 and you get a different one. Come back in six months, type the first string again, and the records match. Change one field in the schema and the values after it shift, because the draw order moved, which is worth knowing before you blame the seed.
Dot paths do the nesting
There is no tree editor on this page. A dot inside the field name is the entire nesting syntax. Three rows sharing a prefix collapse into one parent object.
Field name Typeshipping.street Street addressshipping.city Cityshipping.postcode Postcode
"shipping": {"street": "84 Mill Lane","city": "Rotterdam","postcode": "3011 KP"}Nesting runs as deep as you write it. The key style select renames every segment at once, so a schema typed in camelCase exports as snake_case without editing a single row.
Records hold together
Most mock data pages pick each field on its own. That is how you end up with a record named Priya Sharma whose email reads bruno.keller@example.net, sitting at a Toronto address with a German postcode. This generator draws one identity and one place per record, then reads the related fields off them.
- Full name, first name, last name, email and username all trace back to the same person, so an assertion on
email.startsWith(firstName)holds. - City, country, postcode and the phone country code come from the same place. A Toronto record carries a Canadian postcode pattern and a +1 dial code, an Osaka record carries a 3 digit and 4 digit Japanese postcode and +81.
- Generated addresses land on example.com, example.org and example.net, the domains RFC 2606 reserves for documentation. A staging mailer pointed at this data reaches nobody.
Pick the shape before you copy
Four output shapes cover most of what a stub needs:
- JSON array of records. The default, and what a list endpoint returns.
- Wrapped payload with meta. Records sit under a
datakey next to ametablock holding the count, the seed and the build date. Use it when you are stubbing an envelope rather than a bare list. - Single object. The first record on its own, sized for a detail endpoint response or a config fixture.
- NDJSON. One minified record per line, which is the format BigQuery loads, Elasticsearch bulk indexes and most log shippers read. Pretty printing is skipped there on purpose, since a line break inside a record breaks the format.
What each field type produces
- Identifiers
- Auto increment ID, UUID v4 shape, Mongo ObjectId and SKU codes. The counter starts at 1, or at whatever number you type into the options column.
- Numbers
- Integers, decimals, prices and booleans. Set the bounds as
1-1000or9-899. Integer arrays take a length range instead of a value range. - People
- Full name, first name, last name, email, username and phone, every one of them read off the single identity drawn for that record.
- Places
- Street, city, country and postcode, with the postcode formatted for the country the record landed in across twelve locales.
- Business
- Company, job title, product name, currency code, plus a list picker. Type your own values as
active, pending, archivedand one gets chosen per record. Numeric entries stay numbers, so a status code list gives you404rather than"404". - Text
- Single words, sentences, paragraphs, tag arrays and slugs, all built from a pool of technical nouns so the filler reads as filler.
- Time
- ISO dates, full ISO timestamps, future dates and Unix milliseconds. The options column sets how many days back or forward the value sits, counted from midnight today, so an offset of zero days lands somewhere inside the current day rather than strictly before this minute.
- Web
- URLs, request paths, IPv4 addresses and hex colours, useful for log and analytics fixtures.
Where this generator stops being the right tool
Six limits worth reading before you build a test suite on the output:
- The UUIDs carry the correct version and variant nibbles, but they come from the seeded generator rather than
crypto.getRandomValues(). Reproducible by design, which is the opposite of what a stored key needs. For identifiers headed into a database, use the UUID generator instead. - Nothing links one run to another. A
customerIdin an orders set has no matching row in a users set. Build both sides from one schema, or patch the join keys after export. - Arrays of objects are out of reach. Dot paths nest objects, and the array types return strings or numbers, so an order carrying three line item objects needs a second run pasted into place.
- The ceiling is 1000 records per run, and syntax colouring switches off above 200 KB to keep the tab responsive. Seeding a million rows belongs in a script against your database, not in a browser tab.
- Names, streets and sentences are English. This output will not stress a right to left layout, a CJK column width or a name field that has to survive an apostrophe.
- Date fields count backwards from midnight today, not from a fixed epoch. A seed reproduces byte identical output all day and then slides by one day tomorrow. If a test asserts on a literal date, write that value in by hand after export.
One habit worth keeping
Record the seed in a comment next to the fixture it produced. A dataset whose seed nobody wrote down turns back into random data the moment someone regenerates it, and the reason a given record looked odd goes with it.
Where the output goes next
Send a generated array through the JSON formatter if you want a different indent width, or the JSON viewer to walk the tree before committing it. The JSON to Schema converter turns a sample into a contract you validate against, and JSON to TypeScript gives you the matching interfaces. For a spreadsheet handoff there is JSON to CSV, and JSON Path Tester checks a query against the data before it reaches your code. Everything else sits under all JSON tools.
