Mock Data Generator
Generated in your browser and never transmitted. Names are fictional, phone numbers use the reserved 555-01xx range, and IP addresses come from the RFC 5737 documentation blocks - nothing here belongs to a real person or host.
Nothing you enter here is stored, logged or shared.
Define the fields you need and generate up to 1,000 rows of realistic fake data as JSON, CSV or SQL insert statements. Everything is generated in your browser, so nothing is uploaded and no real personal data is involved.
How to use
- Name each field and choose the kind of value it should hold.
- Pick how many rows you need and whether you want JSON, CSV or SQL.
- Press Generate, then copy the result.
Why the reserved ranges matter
Every generated value is drawn from a range formally set aside for fiction, and this is not pedantry - it is the difference between a test suite that is safe to run and one that is not.
Phone numbers use +1-555-01xx, the hundred-number block the North American Numbering Plan reserves for fictional use; the rest of 555 was released for real assignment years ago, so the old habit of using any 555 number is no longer safe. Email addresses and URLs use example.com, example.org and example.net, reserved by RFC 2606 and guaranteed never to be registered by anyone. IP addresses come from the RFC 5737 documentation blocks, which are not routed.
The failure this prevents is well documented and keeps happening: a test run against a fixture set full of plausible-looking addresses sends real email to real people, or a load test dials real phone numbers, or a seeded staging database gets pointed at a live SMTP relay. Fixtures that cannot reach anybody are a structural fix for that, rather than a procedural one.
Fixtures that actually find bugs
Uniformly reasonable data is comfortable and not very useful. Every name six to ten letters, every string ASCII, every optional field populated: a suite built on that passes and tells you nothing about what happens in production.
The cases worth adding by hand once you have a base set: empty strings and nulls in every nullable column, because those take different paths. Names with apostrophes, hyphens and non-Latin scripts, which is where encoding bugs and naive escaping surface. A value at exactly the column length and one a character over. Dates at boundaries - end of month, end of year, 29 February, the day a daylight saving transition happens. Duplicate values in fields you assumed were unique. A single very large record among small ones.
Generated data gives you volume and shape quickly, which is what you want for pagination, sorting, index behaviour and rendering. The awkward rows are what you want for correctness, and they are usually worth writing deliberately rather than hoping a generator produces them.
The three output formats
JSON is the one to reach for when the destination is code: an API fixture, a mock server, a seed script, a file a test reads at startup. Records come out as an array of objects with your field names as keys.
CSV suits bulk import paths - a spreadsheet, a database COPY, an admin upload form - and is the right choice when you want to eyeball the data as a table before loading it. The usual CSV caveats apply at the far end: a consumer that guesses types will make its own decisions about anything that looks numeric.
SQL emits plain INSERT statements against the table name you give, one row each, which runs in any client without a driver or a script. String values are escaped by doubling quotes, numbers are written bare, booleans as TRUE and FALSE, and identifiers that are not bare words are double-quoted. For a large seed you may want to wrap the output in a transaction, since a thousand individual statements outside one is slow on most engines.
Do not anonymise production data instead
The tempting shortcut when you need realistic test data is to take a copy of the production database and scrub the personal fields. It is worth understanding why this keeps going wrong.
Removing names and email addresses does not de-identify a dataset. Combinations of ordinary attributes - postcode, birth date, sex; or a handful of timestamps and locations - are frequently unique to one person, and the research on re-identifying supposedly anonymous datasets is extensive and consistent. Meanwhile the scrubbed copy is a full-fidelity production dataset living in an environment with weaker access controls, wider developer access, and backups nobody is tracking.
Generating from the schema avoids the whole category. The data has the right shape and no provenance, so a leak from staging is an incident about nothing. Where you genuinely need production-like distributions, the defensible version is to model the statistics and generate from the model rather than to transform the records.
Designing a dataset rather than filling columns
Realistic test data is not random data; it is data whose shape matches production. Real tables are skewed: most customers have one order and a handful have thousands, most documents are short and one is enormous, most sessions last a minute and a few last a day. A fixture where every customer has exactly three orders will never surface the query that falls over on the customer with four thousand.
Volume matters for the same reason. Pagination, sorting and index behaviour are invisible at fifty rows and obvious at fifty thousand, and a page that renders instantly with a short list can take seconds with a realistic one. Generating an order of magnitude more than you expect is the cheapest load test available.
Referential integrity is the third piece. Orders need customers that exist, comments need posts, and child records need parents with plausible dates - an order placed before its customer signed up is a row that will confuse every report built on it later.
Seeding, determinism and repeatability
A test that generates fresh random data on every run fails intermittently, and an intermittent failure is worse than a consistent one because nobody can reproduce it. The usual discipline is a fixed seed: the same sequence every run, so a failure is repeatable and a bisect is meaningful.
That conflicts with wanting varied data, and the compromise most teams settle on is a seeded generator whose seed is printed in the test output. Runs are reproducible when you need them and varied over time, and when a rare combination breaks something the seed in the log reconstructs it exactly.
Seed scripts should also be idempotent. Running the seed twice should leave the database in the same state rather than doubling every table, which in practice means truncating first or upserting on a natural key. A developer who has to drop the database to re-seed will avoid re-seeding, and stale local data is its own category of bug.
Fixtures, factories and snapshots
Three patterns dominate, and they solve different problems. Fixtures are static files loaded before a test: predictable, easy to read, and awkward to maintain because a schema change means editing every file. Factories build objects in code with sensible defaults and per-test overrides, so a test states only the fields it cares about - the widely used approach in most modern suites.
Snapshots capture the output of a function and assert it does not change. They are excellent for rendering and serialisation, and dangerous when nobody reads the diff: an updated snapshot that enshrines a bug is a common failure mode in large suites.
Generated data of the kind this tool produces sits underneath all three. It fills the bulk - the thousands of rows that make performance and pagination realistic - while the specific awkward records are written by hand, because the case that broke production last month is worth stating explicitly rather than hoping a generator reproduces it.
Why copying production data keeps going wrong
Taking a production dump and blanking the names feels like the fastest route to realistic data, and it fails for reasons that are structural rather than procedural. Removing direct identifiers does not de-identify a dataset: combinations of ordinary attributes such as postcode, birth date and sex are frequently unique to one person, and the research on re-identifying supposedly anonymous datasets is extensive and consistent.
The operational problem is separate and just as serious. The scrubbed copy is a full-fidelity production dataset living in an environment with weaker access controls, broader developer access, and backups nobody is tracking. Under GDPR, pseudonymised data is still personal data and still in scope; this is a general observation rather than legal advice, and the details depend on your jurisdiction and your data protection officer.
Generating from the schema sidesteps the whole category. The data has the right shape and no provenance at all, so a leak from staging is an incident about nothing. Where production-like distributions are genuinely needed, the defensible version is to model the statistics and generate from the model rather than transforming real records.
Loading the output where it needs to go
For a database, the SQL output runs in any client without a driver, and wrapping it in a transaction makes a large seed dramatically faster - a thousand individual statements outside one is slow on nearly every engine. For PostgreSQL specifically, COPY from a CSV beats INSERT statements by a wide margin once the row count passes a few thousand.
For an application, JSON is usually the right target: a fixture file the test loads at startup, a response for a mock server, or a seed script the ORM consumes. Field names come through exactly as configured, so matching them to the model's property names saves a mapping step.
CSV is the format for the paths that involve a human - a spreadsheet to eyeball before import, an administrative upload form, a bulk import tool. Just remember the usual CSV caveats at the far end: a consumer that guesses types will make its own decisions about anything that looks numeric, and leading zeros in reference numbers are the usual casualty.
Frequently asked questions
- Is the generated data safe to commit to a repository?
- Yes, and that is deliberate. Names are drawn from a fictional pool, phone numbers use the +1-555-01xx range the North American Numbering Plan reserves for fiction, email addresses and URLs use the example.com family reserved by RFC 2606, and IP addresses come from the RFC 5737 documentation blocks. Nothing generated here routes to a real host or dials a real person.
- Why not just ask an AI assistant for test data?
- For three rows, do. For 500 rows with a fixed schema you need repeatability and exact column names, which is what a generator gives you and a chat does not. It is also faster to change one field type and regenerate than to re-prompt, and the output here never leaves your machine.
- What is the difference between mock, fake and test data?
- In practice, nothing - the three terms name the same thing and this page serves all of them. What matters is the shape: structured records with named, typed columns, as opposed to placeholder prose like lorem ipsum, which fills a layout but cannot be loaded into a database or an API.
- How do I load the SQL output?
- The output is plain INSERT statements against the table name you enter, one row per statement, so it runs in any SQL client. String values are escaped by doubling quotes, numbers are unquoted, and booleans are written as TRUE and FALSE. Column or table names that are not bare identifiers are double-quoted.
- Why is the row limit 1,000?
- A thousand rows of JSON is already around 100KB of text, which is the point where holding it in a text area starts to feel slow. If you need more, generate several batches - the ID column restarts at 1 each time, so adjust it if you are loading them into one table.
- Is the randomness any good?
- It comes from crypto.getRandomValues with rejection sampling, the same unbiased source this site uses for password and UUID generation. That matters less for fake city names than it does for passwords, but keeping one random implementation means there is only one to get right.
Last updated:
Include the steps, expected result, and actual result. Remove secrets and personal data.
