Fake people for test databases, fixtures and demos: names, addresses, emails, phone numbers, birthdates, companies and bank details that are consistent per locale and per row, as JSON, CSV or SQL. The seed makes every batch reproducible, and everything is generated in this tab from bundled word lists, so no real person and no server is involved.
How to use this generator
Pick a locale, toggle the fields you need, choose an output format and set the row count; the result updates as you go and regenerate draws a fresh seed. Copy the output or download it as a .json, .csv or .sql file. The defaults produce what a typical users fixture wants: name, email, street, city with postcode, phone and birthdate.
The part other generators skip is that each row is consistent with itself. The email is derived from the row's own name, with umlauts transliterated the way real systems do it, so Jonas Müller becomes jonas.mueller@example.com and never a random alice91@… next to a different name. Postcode and city are real pairs, the phone number carries the area code of that same city, the age field always matches the birthdate, and German job titles use the form that fits the first name (Softwareentwicklerin for Anna, Softwareentwickler for Jonas). Emails are unique within a batch, so a UNIQUE constraint on the column does not reject row 812 of your import.
Two details worth knowing: toggling a field on or off never reshuffles the other columns, because every field is drawn for every row whether it is shown or not. And the UUID field comes from the same seeded stream, so even the ids reproduce.
Why production data fails as test data
The tempting shortcut is a database dump: production data has realistic distributions, real edge cases and zero setup. It is also the shortcut that turns a harmless staging environment into a liability. GDPR article 5(1)(b) says data may only be processed for the purpose it was collected for, and 5(1)(c) says processing should involve as little personal data as necessary. Debugging a checkout flow was not the purpose anyone consented to, and a full customer table in a test system is the opposite of minimal.
The risk is not theoretical paperwork. Test and staging systems get weaker passwords, broader team access, third-party contractors, disabled TLS, forgotten snapshots on developer laptops. When one of those leaks, it is a reportable breach with real people in it, and the awkward question from the regulator is why the data was there at all. The two clean answers are anonymisation, which is genuinely hard to do irreversibly (see the FAQ on anonymized vs synthetic data), and synthetic data, which sidesteps the whole problem: a record that never described a person cannot expose one.
Both approaches show up on client projects, and only one of them ages well: use synthetic data for everything functional, and if a test truly needs production-like distributions, treat that one dataset as production, with the same access controls and a deletion date.
Locale consistency beats variety
Most fake-data tools default to US-shaped output, and a German or Austrian project notices immediately. A five-digit ZIP like 90210 fails an Austrian postcode check (four digits), a state abbreviation has no column to live in, and (212) 555-0147 fails every +49 phone validator in the codebase. Test data that your own validation rejects is worse than useless, because now the fixtures need special-casing that production data never gets.
This generator treats the locale as the contract for the whole row. de-DE means German names with umlauts, streets like Hauptstraße 12 with the number after the name, real five-digit postcodes correctly paired with their city, including the leading-zero ones like 04109 Leipzig and 01067 Dresden that spreadsheets love to truncate, and +49 numbers with the drawn city's own area code. de-AT swaps in Austrian names, four-digit postcodes (1010 Wien, 8010 Graz) and +43 numbers. en-GB builds postcodes from real outward codes (SW1A, M1, LS1) with a rule-correct inward half, and en-US produces city, state and ZIP as a matching triple with the city's area code.
The umlauts are not decoration. Names like Müller, Schäfer and König walk through every encoding boundary in the stack, database collation, CSV import, email transliteration, PDF export, and that is exactly where bugs hide from tests that only ever saw John Smith. If your app serves the DACH market, fixtures without special characters test a product you are not shipping.
The seed: same data, every run
Every batch is drawn from a seeded pseudo-random generator, not from Math.random(). The seed field shows the seed of the current batch, a fresh random one on every visit, and any text you type replaces it. Same seed, same locale, same fields, same row count: the identical output, byte for byte, on any machine. Under the hood a small string hash (xmur3) turns the seed into 32 bits of state for a mulberry32 PRNG, the same widely used two-liner you would reach for in a game or a test harness.
Reproducibility sounds academic until the third time a test fails only on Tuesdays. Concrete uses: a bug report can say "seed k3f9q2w7x0, row 4" instead of attaching a CSV; CI can regenerate fixtures at test time instead of committing generated files to the repository; documentation examples stay stable across edits; and a flaky test caused by data-dependent behaviour becomes reproducible the moment its data is. Randomness without a seed is where flaky tests come from, randomness with a seed is a feature.
One honest caveat: birthdates are anchored to today so that the age column is always exactly right, which means a seed reproduces byte-identically within the same day. Every other field has no date dependency at all. If you diff generated files in CI, either pin the fixture file or drop the birthdate column.
JSON, CSV and SQL output
The --json format is an array of objects, two-space indented, ready for fixture files, API mocks and seed scripts. Field names are stable snake_case keys, and age is a number, not a string:
{
"first_name": "Katharina",
"last_name": "Schröder",
"email": "katharina.schroeder@example.org",
"city": "Leipzig",
"zip": "04109",
"birthdate": "1987-11-23",
"age": 38
} The --csv format follows RFC 4180: a header row, comma separators, CRLF line endings, and quoting only where a value needs it, which matters the moment a company like O'Brien Logistics Ltd or a value with a comma shows up. It opens in Excel without a wizard and imports into Postgres with a plain COPY … FROM … CSV HEADER.
The --sql format emits one INSERT with multi-row VALUES and lets you set the table name. Single quotes in values are doubled the way SQL expects, so O'Brien arrives intact:
INSERT INTO test_users (first_name, last_name, email) VALUES
('Grace', 'O''Brien', 'grace.obrien@example.com'),
('Oliver', 'Patel', 'oliver.patel@example.org'); All three formats serialize the same underlying rows: switching the format never redraws the data, so you can eyeball a batch as JSON and download the same batch as SQL.
Values that cannot reach anyone real
Fake data has a second job besides filling columns: being incapable of causing harm when a test system does something it should not. Every email here uses example.com or example.org, reserved by RFC 2606 precisely so that documentation and test addresses can never route mail to a person. If staging accidentally sends real email, it bounces instead of landing in a stranger's inbox.
Phone numbers follow the same principle where a country provides for it. US numbers come from the 555-0100 to 555-0199 block reserved for fictional use, and UK numbers use Ofcom's drama ranges, 020 7946 0xxx for London, area code plus 496 0xxx for the other covered cities, and 07700 900xxx mobiles elsewhere. Germany and Austria reserve no such ranges, so those numbers are plausible rather than guaranteed-unassigned, formatted with the real area code of the row's city.
Bank details are checksum-valid without belonging to anyone: IBANs pass mod-97 validation for the locale's country with a randomly drawn bank and account part, and since the US has no IBAN, en-US rows carry an ABA routing number with a correct check digit plus an account number. That is enough to get past every format validator; for IBAN structures of other countries and the details of the checksum math, the IBAN generator is the dedicated page.
Browser tool vs faker vs Mockaroo
Faker libraries (Python's Faker, @faker-js/faker) are the right tool when generation happens inside code: thousands of rows, custom providers, data built per test at runtime. The costs are a dependency in the multi-megabyte range once locale data ships along, one more thing pinned in the lockfile, and for the JS ecosystem a package history that includes the original faker.js being sabotaged in 2022. For "I need 50 German users in a fixture file", importing a library is ceremony.
Mockaroo and similar schema services cover an impressive catalogue of field types and can model whole schemas, but generation runs on their servers and repeatability hangs on a saved schema in an account, not on a seed you can paste into a bug report. This tool sits in the gap: no install, no account, no upload, locale-consistent rows and a seed that makes them reproducible, which is the one property neither big alternative gives you for free.
What this tool does not do
Honest limits, so you do not discover them mid-task. The values are drawn uniformly from fixed pools of about 40 names, 25 cities and 20 streets per locale: fine for fixtures, but not statistically representative, so a 1,000-row batch repeats names (emails stay unique) and every city is equally likely, which real populations are not. There is no schema import and no custom field designer; the columns are the toggles you see. Rows are independent people, so there are no related tables, foreign keys or order histories, and the cap is 1,000 rows per batch. If you need Luhn-valid card numbers for payment flows, that is deliberately a separate page, credit card test numbers, and a generator for arbitrary fake JSON structures is on our list.
Test data questions
Is it GDPR-compliant to use production data for testing?
As a rule, no, not without extra safeguards. Customer records were collected for a specific purpose, and GDPR article 5(1)(b) (purpose limitation) plus 5(1)(c) (data minimisation) stand in the way of copying them into a staging database, which usually has weaker access controls, broader developer access and no deletion process. A compliant setup either anonymises the copy so thoroughly that no one is identifiable anymore, which is harder than it sounds, or skips real data entirely and uses synthetic records. Synthetic data, like the rows from this generator, never contained a real person, so GDPR has nothing to attach to.
What is the difference between anonymized and synthetic test data?
Anonymized data starts from real records and strips or transforms the identifying parts; synthetic data is generated from scratch and never touches a real record. The practical difference is re-identification risk: supposedly anonymized datasets have been re-identified repeatedly (the AOL search logs in 2006, the Netflix Prize ratings in 2007, both by linking the remaining attributes to public sources), and under GDPR data that can be re-identified was never anonymous. Synthetic data has no source record to link back to. The trade-off is realism: anonymized data keeps real distributions and edge cases, synthetic data only contains the patterns its generator was built to produce.
How do I generate the same fake data every time (seeded)?
Seed the random number generator, then every draw after it is deterministic. In Python, Faker.seed(42) before creating values; in JavaScript, faker.seed(42) with @faker-js/faker; in plain code, use a seedable PRNG such as mulberry32 instead of Math.random, which cannot be seeded. This generator does the same in the browser: the seed field feeds a mulberry32 PRNG, so the same seed with the same locale, fields and row count reproduces the identical batch byte for byte. Keep the seed in the bug report or fixture file instead of the data itself.
How do I generate fake test data in Python or JavaScript?
Python: pip install Faker, then from faker import Faker; fake = Faker("de_DE"); fake.name() gives a German name, fake.address() a German-style address. JavaScript: npm install @faker-js/faker, then faker.person.fullName() and friends; pass a locale when constructing to keep the data consistent per country. Both libraries support seeding for reproducible output. Note the JS package name: the original faker.js was sabotaged by its own maintainer in January 2022, and @faker-js/faker is the maintained community fork. For a handful of fixture rows, a browser generator saves you the dependency entirely.
Why should test email addresses use example.com?
Because example.com, example.org and example.net are reserved by RFC 2606 and will never route mail to anyone. A made-up address like test123@gmail.com can easily belong to a real person, and the classic incident follows: a staging system with a live mail path sends that stranger password resets or order confirmations, which is both embarrassing and a personal data breach. Reserved domains make that failure mode impossible, and mail to them bounces predictably instead of landing in a real inbox. The same logic exists for phone numbers: the US reserves 555-0100 to 555-0199, and Ofcom reserves UK drama ranges like 020 7946 0xxx.
How many rows of test data do I need?
Match the number to what the test exercises. Unit-test fixtures want 3 to 10 rows, few enough to assert against by hand. Pagination and list UIs want a count just past the page boundary, 21 or 25 rows for a page size of 20, plus the empty and one-row cases. Rendering and query smoke tests are usually honest at a few hundred to 1,000 rows. Real load testing needs production-scale volume and belongs in a script with a seeded library, not a browser tool. More rows than the test inspects only slow the suite down and hide the case that matters.
Are fake names and addresses personal data under GDPR?
No. GDPR applies to information relating to an identified or identifiable natural person, and a generated record relates to nobody; recital 26 explicitly puts anonymous information outside the regulation. A random draw can coincide with a real name, there are only so many Anna Bauers, but without any link to an actual person the record still identifies no one. Two practical cautions: data derived from real records (scrambled or pseudonymised customers) is not fake and stays in scope, and a real personal email or phone number pasted into otherwise fake data makes that row personal data again.