Synthetic test data use cases
Start from the system you need to test, then choose a schema, seed and export format that make the fixture useful—not merely random.
Every workflow below is the same three steps — describe the columns, fix a seed, pick a serializer — and the differences are entirely in the details: which fields, how many rows, where the nulls go, and which format the destination actually wants. Those details are what separate a fixture that finds bugs from one that just fills a table.
Database seeding
Populate local, CI and staging databases with repeatable customers, orders, employees or transactions. Use a fixed seed so every developer starts from the same rows, then export portable SQL inserts or a CSV for bulk loading.
The decision that matters most is size. Up to a few thousand rows, SQL inserts are convenient and self-contained — one file, checked into the repository, applied with a single command. Past that, CSV plus a bulk loader is commonly an order of magnitude faster, because COPY and LOAD DATA bypass per-statement overhead entirely.
The second decision is relationships. Columns are generated independently, so a foreign key will not match a parent row by accident. Generating a related set is a deliberate two-pass job: export the parent table, then paste its key column into a Custom List field on the child schema so every reference resolves. Repeating some parent IDs in that list also gives you the hot-key skew that a uniform draw never produces.
Plan database test data → · PostgreSQL · MySQL · MongoDB
Mock APIs and frontend development
Create typed JSON objects with realistic names, emails, prices, dates, booleans and nulls. Serve the fixture from a local route or test interceptor while a backend is unfinished, or use it to exercise empty, partial and long-value UI states.
Types are the part hand-written fixtures usually get wrong. A file where every value is a string will pass your tests and disagree with the real endpoint, and the disagreement surfaces in production. The JSON export emits numbers as numbers and booleans as booleans, and any field with a Blank % set produces a real null — which is the value most frontend crashes in this area are actually about.
Generate several sizes from one schema: a three-row file for layout, one past your page size for pagination, and an empty array for the empty state. Because they share a schema they stay consistent with each other, which a set of hand-written fixtures never manages for long.
Create mock API data → · Sample JSON data
QA automation and regression fixtures
Combine deterministic seeds with Blank %, unique values, patterns and custom lists. The resulting fixture stays stable across Playwright, Cypress and unit-test runs while still covering missing values and format boundaries.
The reason to generate once and commit, rather than call a fake-data library at runtime, is that runtime randomness turns a real failure into an unreproducible flake. A test that fails once in forty runs gets a retry rather than an investigation, and the bug ships. A seeded file gives you the same realistic variety on every machine, and a known value you can name in an assertion instead of a snapshot you have to trust.
Randomness also finds the interesting cases slowly. Generate the ordinary rows in bulk, then add the specific awkward ones — an apostrophe in a surname, a value at the exact column width, a missing optional field, a leap day — through a Custom List, so a red test points at something nameable.
Design QA test data → · Playwright · Cypress
Excel, Sheets and BI samples
Generate clean tabular samples for formulas, dashboards, import mapping and training. CSV provides broad importer compatibility; TSV is convenient for direct clipboard pastes and comma-heavy text.
Spreadsheets are where uniform random data looks most obviously fake. A pivot table over four equally sized regions and evenly spread dates produces a flat, featureless chart. Three adjustments fix it: set the date field to sequential order so the time axis is clean, weight categories by repeating values inside a Custom List, and use the Number (Normal Dist.) field for amounts so there is a believable middle with real outliers.
The other recurring problem is Excel rewriting your data on import — leading zeros stripped from IDs, dates reinterpreted according to regional settings, long numbers turned into scientific notation. Generating a column of zero-padded identifiers is the fastest way to find out whether your import path has that problem.
Generate spreadsheet sample data → · Sales sample data · Employee sample data
Data pipelines and demos
Use NDJSON for line-oriented ingestion, CSV for ETL tools, or XML for integration contracts. Templates create a believable demo quickly; a seed makes screenshots, tutorials and benchmark runs reproducible.
For pipelines specifically, NDJSON is usually the right answer at volume because it streams — a consumer handles one record at a time rather than parsing a whole array into memory, which is what BigQuery loads, Elasticsearch bulk ingest and jq without --slurp all expect.
Demos have a different requirement: the same data every time. A fixed seed means the screenshot in your documentation matches what the reviewer sees, the number in the tutorial is still the number next month, and a benchmark comparison is measuring your code rather than a different dataset.
Training, tutorials and interview exercises
A fixed seed makes a dataset shareable as a recipe rather than a file: publish the schema and the seed, and every student generates byte-identical rows locally. Exercise answers are then the same for everyone, and nobody is working from a stale download. Because the data is fully synthetic it is also safe to publish, unlike the anonymised production extracts these exercises are often built from.
The same applies to automation practice. This site's own controls all carry stable data-testid attributes that survive deploys, so it doubles as a target for Playwright and Cypress exercises — forms, selects, dialogs, drag-and-drop reordering, file downloads and dynamically rendered rows, without needing a test environment of your own.
Load and performance testing
Generating 100,000 rows is the point at which schema decisions start to matter for reasons other than realism. Wide schemas serialize more slowly than narrow ones; unique constraints on a small value space get expensive; and the format you export changes the load time downstream far more than the generation time upstream.
Two cautions. Uniform data is a poor performance proxy — real workloads are skewed, and a cache that looks effective against evenly distributed keys may not be against a realistic hot-key distribution, which is what weighted Custom Lists are for. And a single export is capped at 100,000 rows; for larger fixtures, export repeatedly with different seeds and concatenate, stripping the header from every file after the first.
Which format for which job
The schema is the same in every case — only the serializer changes, so switching costs one dropdown. This is the shortest version of the decision:
| If you need… | Use | Because |
|---|---|---|
| A spreadsheet or a bulk database load | CSV | Every importer on earth reads it, and COPY/LOAD DATA are far faster than inserts. |
| A clipboard paste or a shell pipeline | TSV | Pastes into a sheet as real columns, and cut/awk need no parser. |
| A test fixture or a mock API response | JSON | Types survive: numbers, booleans and real nulls rather than strings. |
| A streaming or bulk-ingestion pipeline | NDJSON | One record per line, so 100,000 rows cost constant memory and one bad line loses one record. |
| A populated dev database, no ETL step | SQL | psql -f and it exists. Optional inferred CREATE TABLE. |
| A legacy or integration contract | XML | Complete document with a declaration, escaped entities and XPath-friendly structure. |
Three things that make a fixture actually useful
Realistic values are the easy part. What separates a fixture you keep from one you regenerate every time is usually one of these:
-
Set a seed and write it down. A seed turns the export into a
function: same seed plus same schema gives byte-identical output, forever. That is
what makes a committed fixture diff cleanly and a failing CI run reproducible on a
laptop. Name seeds after what they represent —
sprint-42,empty-cart— rather than leaving them blank. - Generate the unhappy path on purpose. Blank % exists because most defects live in missing values, not present ones. A fixture where every field is populated tests the one case you were already confident about. The same applies to long values, international characters and boundary numbers.
- Keep the schema next to the code it feeds. Save the schema, or share the URL — the whole definition is encoded in the link — so the next person can regenerate the fixture instead of guessing what produced it.
Choose safe synthetic fields
Generated emails use reserved domains, network addresses use documentation ranges and sensitive-looking values are explicitly test-only. Read the data methodology and safety notes before using fixtures in shared environments.
This matters beyond tidiness. Synthetic data is the only kind you can safely commit to a repository, paste into a bug report, share with a contractor or put on a screen during a demo — none of which are safe with a production extract, however well intentioned the anonymisation. Starting from generated data removes the question entirely.
How this compares with the other options
None of these workflows require this particular tool, and the honest comparison is a structural one: what changes is where generation happens and what you end up holding. Each of these pages says plainly when the other option is the better answer.
- Against a hosted generator — a server that generates for you, versus a page that generates on your machine.
- Against a library like Faker.js — values produced inside your program at run time, versus a file you download once and commit.
- Against a self-hosted application — infrastructure you control, versus infrastructure that does not exist.
- Against a template-based JSON generator — a template language you write, versus typed fields you pick.
- Against a random user API — records fetched over HTTP when your code runs, versus records already on disk.
Common questions
What is synthetic test data used for?
Filling a system with realistic data when real data is unavailable, unsafe or too slow to get: seeding a development database, mocking an API a frontend is not waiting for, building QA fixtures that fail the same way twice, and making spreadsheets and demos that look like production without containing any of it.
Is synthetic test data safe to commit to a repository?
Yes, when every value is generated rather than derived from real records. Here emails use reserved documentation domains, card numbers are published payment-gateway test PANs, IP addresses come from documentation ranges, and no row describes a real person — so a generated fixture carries no personal data to leak.
How much test data do I actually need?
Enough to make the failure modes visible, which is usually far less than people assume. A hundred rows exercises layout, sorting and null handling; a thousand shows pagination and index behaviour; a hundred thousand is for measuring query plans and import times. Generating more than you will look at mostly slows your own feedback loop.
Can the same dataset be reused across a team?
Yes. Enter a seed and the same schema produces byte-identical output on every machine, so a fixture can be regenerated from a seed instead of stored, and two developers debugging the same row are looking at the same row.
Which export format suits which job?
CSV and TSV for spreadsheets and bulk database loads, JSON for API fixtures, NDJSON for streams and log pipelines, SQL for direct seeding with a CREATE TABLE included, and XML for systems that ask for it. The same schema exports to all six, so the choice is not made when you design it.
Last updated