Mock Data Generator
Build a schema and generate realistic fake data as CSV, JSON, SQL, or XML — seeded, reproducible, entirely on this device.
1 to 1,000,000 rows per run. Same seed + same schema = byte-identical output.
The live preview appears here once the schema is valid.
Output downloads as a file — the page never holds the dataset.
Press ? for shortcuts
Do it offline:$ python3 -m faker -r 3 name
How to use it
- Add one field per column: name it and pick one of the 31 types, grouped into 9 menus — person, internet, location, business, time, numbers, ids, text, finance. Per-type options appear beside it: numeric ranges, float precision, date bounds, timestamp format, enum values with optional weights, and a blank-rate percentage.
- Set the row count — 1 to 1,000,000 — and choose the output format. CSV adds delimiter and quoting controls; SQL adds a table name and a dialect: PostgreSQL, MySQL, or SQLite.
- Pin a seed to freeze the dataset, or leave it empty for fresh values each run — the page mints one and shows it in a "Seed used" chip, keeping even a spontaneous run reproducible.
- The live preview is exactly the first 20 rows of the file you will download. Validation problems appear on the field row they belong to, and Generate stays disabled until they are fixed.
- Press Generate, or ⌘/Ctrl + Enter. Long runs stream in the background with a progress bar and a Cancel that works; the finished dataset downloads as a file, and results up to 1 MB can be copied straight to the clipboard.
Describe the table you need — ids, names, emails, dates, amounts, enums — and this page generates realistic rows on this device as CSV, JSON, NDJSON, SQL INSERTs, or XML. Runs are seeded, so the same schema and seed reproduce the same bytes next month. There is no signup and no server quota, because there is no server doing the generating; the row limit is printed, not hidden: 1,000,000 rows per run.
How it works
Every run seeds one pseudo-random generator; every random decision — field values, blank-or-not draws, enum weighting, the bytes inside uuid-v7 and nanoid ids — draws from that single stream in a fixed order. A seed is therefore a complete recipe: the Share link carries schema and seed (never rows), and another browser rebuilds the identical file, byte for byte.
Generation happens in a background worker, 10,000 rows at a time, each chunk serialized and accumulated off the page thread — the tab never holds a million-row array and stays responsive mid-run. Chunking never reseeds the generator, so a chunked run is byte-identical to a single pass and the preview always matches the first 20 file rows.
CSV cells that begin with =, +, -, @, a tab, or a carriage return get a leading single quote in the output, per OWASP's CSV-injection guidance: a spreadsheet that would have executed =SUM(A1) as a formula shows disarmed text instead. Only text cells are prefixed — numbers and booleans cannot carry a formula, and an apostrophe on every negative number would be corruption, not protection.
SQL output quotes every identifier for the chosen dialect and doubles any single quote inside a string literal, so a generated O'Brien arrives as 'O''Brien' — with backslashes also doubled for MySQL, whose default mode treats backslash as an escape. Blank cells become NULL in all three dialects.
Examples
starter schema: id (uuid-v7), name, email, signed_up (date) · 3 rows · seed 42 · CSVid,name,email,signed_up
019cd20a-cbef-7b99-a727-0edd99b505f8,Clinton Gutmann,Brionna_Klocko@hotmail.com,2025-07-09
019cd20a-cc1e-7b2b-90f2-f7ce4d19af70,Ana Gerlach,Clyde59@gmail.com,2024-03-23
019cd20a-cce2-7b53-a345-d45b478a24cd,Ms. Nova Abshire,Brandy.Harris31@yahoo.com,2025-11-14
Seed 42 with this schema produces exactly these bytes on every run. The uuid-v7 ids sort by their embedded timestamps, the dates stay inside the 2024-01-01 to 2026-07-25 bounds, and every row ends in CRLF per RFC 4180.
same starter schema · 3 rows · seed 42 · SQL INSERTs for PostgreSQLINSERT INTO "users" ("id", "name", "email", "signed_up") VALUES ('019cd20a-cbef-7b99-a727-0edd99b505f8', 'Clinton Gutmann', 'Brionna_Klocko@hotmail.com', '2025-07-09');
INSERT INTO "users" ("id", "name", "email", "signed_up") VALUES ('019cd20a-cc1e-7b2b-90f2-f7ce4d19af70', 'Ana Gerlach', 'Clyde59@gmail.com', '2024-03-23');
INSERT INTO "users" ("id", "name", "email", "signed_up") VALUES ('019cd20a-cce2-7b53-a345-d45b478a24cd', 'Ms. Nova Abshire', 'Brandy.Harris31@yahoo.com', '2025-11-14');
Same seed, same three people — only the serialization changed. Identifiers are double-quoted for PostgreSQL, string values are single-quoted literals, and the table name defaults to users until you set one.
identical schema run twice · 3 rows · seed 7 · CSV — byte-identical outputid,name,email,signed_up
019bbd96-fba0-70b9-ba89-8012447fadcd,Erica Effertz,Vada52@yahoo.com,2025-09-18
019bbd96-fd74-747d-9f7a-5dd6c4509246,Marlene Koelpin,Pedro_Nicolas41@hotmail.com,2024-03-27
019bbd97-003a-76b2-b4ae-0d4f973cf7f1,Russell Hagenes,Geraldine44@yahoo.com,2026-01-16
Determinism is the feature: the build runs this schema twice with seed 7 and verifies the two files match byte for byte. Change the seed and every value changes; change nothing and nothing does.
plan enum weighted 70/25/5 + city with 20% blank rate · 6 rows · seed 8 · NDJSON{"plan":"pro","city":"Marietta"}
{"plan":"free","city":null}
{"plan":"free","city":"Laurenfort"}
{"plan":"pro","city":"Estevanburgh"}
{"plan":"free","city":"West Ireneside"}
{"plan":"free","city":"West Tristianborough"}
The 70/25/5 weights are visible even in six rows — four free, two pro, and the 5% enterprise value happened not to be drawn — and the blank rate left one city null. Both are probabilities — small samples vary — and the seed makes this exact sample repeatable.
enum note: =SUM(A1), quarterly total, @alice · 3 rows · seed 1 · CSV escapingnote
quarterly total
'@alice
'=SUM(A1)
quarterly total passes through untouched, while =SUM(A1) and @alice gain a leading apostrophe — the OWASP defence for cells a spreadsheet might execute as formulas.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A million rows never sit in the page
The interface only ever holds the 20-row preview; generated chunks accumulate off the page thread until the download is handed over. The four-column starter schema at the full 1,000,000 rows is estimated at roughly 87 MB of CSV and still leaves the tab usable — and Cancel genuinely cancels, keeping your schema untouched.
Quotes and newlines are RFC 4180's job
Generated sentences can contain commas, quotes, and line breaks. Any CSV cell containing the delimiter, a double quote, or a newline is wrapped in double quotes with inner quotes doubled, and every row — including the last — ends in CRLF. A quote-all mode wraps every cell for parsers that want uniformity.
Dates are drawn as UTC instants
The date type picks whole UTC days and the timestamp type picks UTC milliseconds inside your bounds, formatted with UTC arithmetic only. Ranges crossing a daylight-saving transition cannot shift by an hour, and a zone-less bound such as 2024-06-01T09:00 is read as UTC — the same schema yields the same instants on every machine.
What a blank cell looks like in each format
A blank is null in the data model and renders per format: an empty cell in CSV, null in JSON and NDJSON, NULL in SQL, and a self-closing empty element in XML. If your CSV shows gaps where your SQL says NULL, both files carry the same blanks in different notations.
uuid-v7 time comes from the seed, not your clock
The timestamps embedded in uuid-v7 values are drawn from the seeded stream — a strictly increasing walk through a fixed window starting 2026-01-01 — never from the wall clock. Ids still sort in creation order, and the same seed mints the same ids tomorrow — exactly what fixtures need.
NDJSON is the pipeline pick
JSON output is one array — convenient to import whole, awkward to stream. NDJSON emits one object per line with no wrapper, so jq, log shippers, and bulk loaders can process the file line by line. Same rows, same seed, different framing.
Half-gigabyte estimates ask first — and can stream to disk
When the size estimate reaches 500 MB, a dialog prints it and asks before running. Browsers with the File System Access API also get a save-straight-to-disk option that writes chunks as they are generated. Elsewhere the file is assembled in memory, and estimates past the 2 GB in-browser limit are refused with a CLI alternative printed.
Copy stops at 1 MB; download does not
Clipboards are the weak link for large payloads, so Copy is offered only up to 1 MB of output. ⌘/Ctrl + C copies the result whenever nothing is selected; the download and ⌘/Ctrl + S carry any size a run can produce.
Common errors
Field 2 duplicates the name "email" already used by field 1 — rename one of them.- Column names must be unique — a duplicate would shadow its twin in every output format. The comparison is exact: email and EMAIL are different names here; case-insensitive collisions are your database's concern.
Field 1 ("score"): min 100 is greater than max 10 — swap the bounds.- Numeric ranges are inclusive on both ends and must be ordered; the same code fires for a date or timestamp whose start is after its end. The refusal is anchored to the offending field row rather than a generic banner.
Field 1 ("plan"): the enum has no values — add at least one value.- An enum column draws from the values you list, so an empty list has nothing to draw. Weights are optional — when present there must be exactly one positive weight per value, and mismatches are reported the same way.
SQL table name "user table" is not a valid PostgreSQL identifier — use letters, digits and underscores, starting with a letter or underscore.- SQL output checks the table and every column name against a conservative portable identifier rule for the chosen dialect — a space in a table name is almost always a typo, so it refuses rather than paper over it. The check only runs when the format is SQL.
Row count 2,000,000 is over the 1,000,000-row cap for this tool — the current schema would be ~173.6 MB of CSV. Lower the row count or generate in seeded batches.- The cap is printed, and the message quotes a size estimate for your exact schema, because the practical ceiling is memory rather than a round number. Seeded batches are the escape hatch the message names.
Estimated output is ~2.6 GB — over the 2 GB in-browser limit, and this browser cannot save directly to disk. Lower the row count or generate in seeded batches. Do it offline: python3 -m faker -r 3 name- This banner appears when the estimate exceeds what an in-memory download can hold and this browser offers no streaming save. Where the File System Access API exists, the confirm dialog writes chunks directly to disk instead, and the banner never appears.
FAQ
How many rows can I generate at once?
1,000,000 per run, and the limit is printed rather than discovered: the refusal quotes the cap and a size estimate for your schema. No account tier or server quota sits behind it — rows are generated by your browser, not a metered API. Need more? Run several seeds and concatenate the files; each batch is independently reproducible.
Is the generated data real?
No. Names, addresses, and companies come from Faker's fictional corpus, shaped like the real thing — emails parse, IBANs pass the mod-97 check, uuid-v7 ids carry correct version and variant bits — while identifying nobody. Two cautions: generated emails can use real mail domains, so never actually send to them, and a fictional IBAN does not belong in a payment system.
Can I reproduce the same dataset later?
Yes — that is what the seed is for. A run is fully determined by the schema and seed together; if you left the seed empty, the page minted one and shows it in the "Seed used" chip, so even that run stays reproducible. Share writes schema and seed into the link, making a permalink a complete fixture recipe.
Does my schema or the generated data leave this device?
Generation is local: once the page and its generator chunk have loaded, producing data makes no network request — the network tab will show you. The dataset exists only in this tab and in files you save. Share encodes the schema (fields, options, seed) into the URL fragment — never rows — so pass a link around as you would the schema itself.
What is CSV injection, and why do some cells start with an apostrophe?
Spreadsheets execute cell text beginning with = or @ as formulas — a classic attack vector when a CSV reaches Excel. Following OWASP guidance, text cells starting with =, +, -, @, tab, or carriage return get a leading single quote, which spreadsheets show as plain text; numeric and boolean cells cannot carry a formula and are left alone.
How do the PostgreSQL, MySQL, and SQLite outputs differ?
Identifier quoting: double quotes for PostgreSQL and SQLite, backticks for MySQL. Booleans: TRUE and FALSE, except SQLite, which prints 1 and 0. Escaping: single quotes double in every dialect, and MySQL also doubles backslashes since its default mode treats them as escapes. Blanks are NULL in all three.
What does the blank rate do?
It makes a column realistically incomplete. A blank rate of 20 leaves each cell empty with 20% probability, drawn from the same seeded stream as everything else, so even the gaps reproduce. Set 100 to blank a whole column; 0, the default, means none.
Is this a free Mockaroo alternative?
For schema-built CSV, JSON, SQL, and XML fixtures, yes: typed fields, row count, download. The difference is that generation runs in your browser — no account, no per-plan row allowance, no upload of whatever your schema names reveal. The 1,000,000-row cap is a memory limit printed on the page, not a pricing tier.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Generate from the current schema, rows, format, and seed.
- ⌘/Ctrl + S
- Download the last generated file again — or generate first when there is none.
- ⌘/Ctrl + C
- Copy the output when nothing is selected and it is 1 MB or smaller; selections still copy normally.
- ⌘/Ctrl + Shift + C
- Copy the output even while a selection is active (same 1 MB limit).
- t
- Cycle the color theme (outside input fields; single-key shortcuts can be disabled).
- ? or ⌘/Ctrl + /
- Open the shortcut help overlay.
- Esc
- Close an open dialog. Cancelling a run is a button, never a key.