Fake JSON Data Generator_

Generate fake JSON records for a test, a fixture or a mock API — from a seed, so the same seed gives you the same records tomorrow, in CI, and in six months.

Every address it invents is in a range reserved for exactly this: emails at example.com, hosts at example.org, IPs in 192.0.2.0/24. Nothing generated here can reach a real person or a real server.

toolkit.codes/json-generator
Fields
Add a field to begin
UTF-8
Ready
100% LOCAL
Input
A list of fields with a type each, a record count, and a seed — any word will do.
Output
The records as a JSON array, wrapped in an object, or newline-delimited.
Processing
Generated in this tab from a seeded pseudo-random sequence. No API, no quota, no account.
Limits
Up to 1000 records at a time. Every field is drawn independently, so nothing here has the correlations real data has — this is a fixture, not a sample.
Reproducible on purpose
The UUIDs come from the seed rather than from crypto. That makes them repeatable, which is the point for a fixture and disqualifying for a real identifier.

A fixture you can regenerate beats one you have to store

Fresh random data every click is the problem

Most generators hand you a new set on every press, which is fine for filling a screenshot and useless for a test. Anything asserting against that data has to be rewritten whenever somebody regenerates it, so the output gets pasted into the repository once and then rots — nobody dares touch it, and by the second year it describes a schema that no longer exists. A seed removes the dilemma: the fixture becomes four lines of configuration rather than four hundred lines of committed JSON, and regenerating it is not a decision anybody has to weigh up.

Reproducibility is what makes a failure investigable

A test that fails against randomly generated data tells you something is wrong and not what. With a seed the failing case is a value you can print, put in the ticket and hand to somebody else, and they will see the same thing. This is the same reason property-based testing frameworks print the seed on failure — the generated input is only useful as evidence when it can be reproduced on demand.

Test data that can reach the outside world eventually does

A generator that emits gmail.com addresses and routable IP addresses is handing you a fixture that will, the first time a staging job is pointed at the wrong SMTP host, email a stranger. RFC 2606 reserves example.com, example.org and example.net, and RFC 5737 reserves three address blocks, precisely so that documentation and test data cannot collide with anything real. Using them costs nothing and removes an entire category of incident, so everything invented here comes from those ranges and the tests assert it.

And it is still not your data

Generated records carry none of the shape of the thing they imitate. Real tables have hot keys, repeated values, nulls clustered in the rows written by one broken importer, and a long tail; every field here is drawn independently and near-uniformly. So this fills a layout, exercises a parser and populates a demo honestly, and a load test against it measures an access pattern your database will never see. That is worth knowing before the graph goes in a slide.

Describe the record, then take the seed with you

  1. 01Add a field for each key you need and pick its type. The id type counts up from 1; everything else is drawn from the seed.
  2. 02Set the record count and choose a shape — a bare array for a fixture, wrapped in an object for an API response, NDJSON for a log or a bulk import.
  3. 03Give a seed you will remember. Any word works, and the same word always produces the same records.
  4. 04Copy the output, or better, note the seed and the field list and regenerate it whenever you need it — that is the version that does not go stale.

What people generate this for

A fixture that stays put

A test needs twenty users and needs them to be the same twenty.

Store
the seed, not the JSON
Result
a fixture that cannot drift

A layout under pressure

Checking a table before the real content exists.

Use
paragraph and sentence
Finds
the row that assumed one line

A bulk import

A thousand rows to push through an ingestion path.

Shape
NDJSON
Which
streams line by line

A schema from the result

You need the JSON Schema for what you just generated.

Paste into
the JSON Schema generator
Which
infers it from the samples

The field types, and what each one promises

TypeProducesWorth knowing
ididA sequential integer starting at 1 — the one field that is not random, because a primary key that jumps is not a realistic fixture.
uuiduuidVersion 4 in shape, generated from the seed rather than from crypto, so it is reproducible. Do not use these as real identifiers.
firstNamefirst nameFrom a short list of computing figures. Obviously invented, which is the point — a fixture that reads like a real customer list is one somebody will eventually treat as one.
lastNamelast nameSame list. Names are the field people most often fill with plausible real ones, and plausible is exactly wrong for test data.
fullNamefull nameFirst and last joined, drawn independently — so the same person appears under different surnames across records, which is correct for a fixture and wrong for anything pretending to be a population.
emailemailAlways @example.com, reserved by RFC 2606 so a misconfigured job cannot email a real person.
usernameusernameLowercase, from the name lists, with a number appended so two records rarely collide on it — usernames are unique in most schemas and a generator that ignores that produces fixtures that fail insertion.
phonephoneUses the 555-01xx range, set aside for fiction so it cannot ring anybody.
streetstreet addressA house number and a deliberately fictional street name, so nothing here resolves to a real address in a geocoder.
citycityPlaceholder towns rather than real ones, so a fixture cannot be mistaken for a customer list if it ever escapes into a report.
countrycountryInvented countries. A real country name in test data ends up in somebody’s analytics.
companycompanyInvented companies, for the same reason as the countries — a real trading name in a fixture is a trademark somebody else owns.
jobTitlejob titleA short generic list. Deliberately not seniority-tagged, because a title field is one people filter on and a skewed distribution invents a finding.
wordwordOne lorem word, for when a field needs to be short and meaningless rather than sentence-shaped.
sentencesentenceSix to twelve lorem words, capitalised, with a full stop — long enough to wrap in a narrow column, which is usually what you are testing.
paragraphparagraphThree to five sentences, which is long enough to overflow a layout that assumed one line — often the reason for generating it.
integerintegerBetween min and max inclusive, defaulting to 0 and 1000. Set a range that matches your column, or a smoke test passes on values the real constraint would reject.
floatfloatTwo decimal places, between min and max. Stored as a JSON number, so anything needing exact decimal arithmetic wants a string column instead.
pricepriceTwo decimal places, and never ending in .00 — a column of round numbers is the tell that data is generated.
booleanbooleanTrue or false, evenly. Real boolean columns are almost never even, which is worth remembering before benchmarking an index on one.
datedateISO 8601 date within the last two years of a fixed instant, so the same seed gives the same dates rather than drifting with the clock.
datetimedatetimeISO 8601 with a Z offset. Always UTC, because a fixture with a local offset breaks in another timezone.
urlurlAlways under example.org, reserved by RFC 2606.
ipv4ipv4From 192.0.2.0/24, reserved by RFC 5737 for documentation — it routes nowhere.
colourcolourA hex colour from a fixed palette, chosen to stay distinguishable when a chart renders several of them side by side.
statusstatusOne of active, pending, archived, suspended — an enum, which most schemas have and most generators do not offer.

Ranges are configurable on the numeric types, and any field can be made nullable at a rate you choose — because real columns are, and a fixture with no nulls in it never exercises the branch that handles them.

Getting a fixture that stays useful

  • Commit the seed and the field list, not the output. A regenerable fixture is one people are willing to change; a committed blob is one nobody touches.
  • Name the seed after what it is for — orders-empty, users-with-nulls — so the fixture explains itself in the test that uses it.
  • Turn on a null rate for anything nullable in your schema. A fixture with no nulls never reaches the branch that handles them, which is where the bug is.
  • Set the numeric ranges to match your real constraints. A smoke test that passes on values the database would reject has told you nothing.
  • Use NDJSON for anything you intend to stream or bulk-load. One object per line means a failure names the line rather than failing the whole file.
  • Feed the output into the JSON Schema generator if you need a contract, and the CSV converter if the thing consuming it wants a spreadsheet.

Before you use generated data for anything

This is not anonymised data

There is no real data here to anonymise. Generated records carry none of the distribution, skew or correlation of the thing they imitate, so a query that is fast against them can be slow against production and a validation rule that passes here can fail on the first real row.

Uniform randomness is not a workload

Real tables have hot keys, repeated values and long tails. Every field here is drawn independently and near-uniformly, so a load test against it measures an access pattern your database will never see — usually a flattering one.

Reserved ranges exist so fixtures cannot reach anybody

Emails end in example.com and addresses come from 192.0.2.0/24 because RFC 2606 and RFC 5737 set those aside for exactly this. A generator that emits gmail.com addresses hands you a fixture that will email a stranger the first time a staging job points at the wrong SMTP host.

The UUIDs are reproducible, which means they are not unique

They are generated from the seed rather than from a cryptographic source, so the same seed gives the same UUIDs. That is the point for a fixture and disqualifying for anything else — never let one of these become a real identifier.

How it is generated, and what is guaranteed

Randomness
A seeded xorshift32 sequence. Not cryptographic and not trying to be — reproducibility is the requirement here, and those two goals are opposites
Seed
Any text. It is hashed to a 32-bit value, so orders-v2 works as well as a number, and the same string always gives the same records
Reserved ranges
Emails at example.com and hosts at example.org per RFC 2606; IPv4 from 192.0.2.0/24 per RFC 5737; telephone numbers in the 555-01xx fiction range. Asserted in the test suite against a list of real providers
Dates
Drawn relative to a fixed instant rather than to the clock, so a fixture generated today diffs cleanly against one generated last month. Datetimes are always UTC
Nulls
Per-field, at a rate you set. The draw happens whether or not the null is used, so switching one field to nullable does not change the values of every field after it
Duplicate keys
Renamed rather than dropped, and reported. A repeated JSON key silently overwrites the first, which would quietly cost you a column
Ceiling
1000 records per run. Past that this stops being a browser task and becomes a script — and a seeded generator is easy to reimplement in ten lines wherever you need it
Network
None from tool code. A test sweep calls every function this page uses with fetch and XMLHttpRequest replaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.

Questions about generating mock data

Why does this use a seed?

So the same input gives the same records. A fixture you can regenerate is one you are willing to change; a blob of random JSON committed to the repository is one nobody dares touch, and by its second year it describes a schema that no longer exists. It also makes a failure investigable — the failing case is a seed you can put in the ticket rather than data nobody can reproduce.

Are the email addresses safe to use?

Yes, and that is deliberate rather than incidental. Everything is at example.com, which RFC 2606 reserves so it can never be registered by anybody. A generator emitting gmail.com addresses gives you a fixture that will email a stranger the first time a staging job points at a real SMTP host, and that is a common enough accident to design against.

Can I use these UUIDs as real identifiers?

No. They are generated from the seed rather than from a cryptographic source, which is exactly what makes them reproducible — and it means the same seed produces the same UUIDs every time, so they are not unique in any sense that matters. Use crypto.randomUUID or the UUID generator for anything real.

Is this good enough for a load test?

For exercising a code path, yes. For measuring performance, no, and the reason is not the volume. Every field here is drawn independently and near-uniformly, while real tables have hot keys, repeated values and long tails — so an index behaves differently, a cache hits differently, and the number you measure is usually flattering.

What is NDJSON for?

Streaming and bulk loading. One JSON object per line means a consumer can process records as they arrive without holding the whole file in memory, and a malformed record names its line instead of invalidating the document. It is what most log pipelines and bulk import endpoints expect.

How do I get a schema for the data?

Generate the records, then paste them into the JSON Schema generator, which infers a schema from the samples and tells you where it had to guess. Going the other way — records from an existing schema — is not what this does; the fields here are described directly.

Is anything I configure here sent anywhere?

The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.