Free online JSON Schema generator
JSON to JSON Schema, with the guesses spelled out
This generator is free and needs no signup: paste a sample payload of up to 5 MB and it writes a draft 2020-12 JSON Schema with the types, the nested objects, the required keys, the enum candidates and the string formats already filled in. Array elements are folded into a single items schema, so twelve records describe the shape better than one does. What separates it from a one-click generator is the list underneath the result: every assumption the sample could not settle — an optional key, an empty array, a field that was only ever null, an enum that may be a coincidence — is written out so you know exactly what to tighten before the schema goes anywhere near CI.
- 100% free
- No signup
- Draft 2020-12
- Up to 5 MB
- Enums and formats
The inferred schema appears here.
Paste a payload, drop a file, or press Ctrl+V anywhere on this page.
How to generate a JSON Schema from JSON
Three steps from a sample payload to a schema worth committing.
Paste the most representative payload you have
An array of records beats a single object, because optionality can only be observed: a key missing from one element of twelve is what tells the generator the field is optional. Paste it, drop a .json file on the editor, or use the clipboard shortcut — Ctrl+V, ⌘V on a Mac — from anywhere on the page. Up to 5 MB is read, and the sample button loads an order payload with a nested object, a four-element array and an empty list in it.
Set the strictness before you copy anything
Required decides which observed keys land in the required array — keys present in every object, every key seen anywhere, or none at all. Strict objects adds "additionalProperties": false. Enum detection offers a closed value list where a field kept repeating the same few strings, and the limit beside it sets how many distinct values still count as an enum. Formats, integer-versus-number, array bounds and examples each have a switch of their own.
Read the notes, then tighten the schema by hand
Underneath the result is a list of everything the sample could not settle: fields left out of required and why, arrays that were empty so their items stayed open, values that were only ever null, and any enum the generator guessed at. Copy or download the schema, fix those points, then run a second payload through the JSON Schema validator to see which guess was too strict.
Technical specifications
| Dialect | JSON Schema draft 2020-12, declared as https://json-schema.org/draft/2020-12/schema |
|---|---|
| Keywords written | type, properties, required, items, enum, format, additionalProperties, title, minItems, maxItems and examples — the last three behind switches |
| Types | object, array, string, integer, number, boolean and null, with a type array where a field held more than one; integer only where no fractional value was seen |
| Formats detected | uuid, date-time, date, time, duration, email, ipv4, ipv6, uri and hostname — applied only when every sampled string of that field matches |
| Enum rule | A scalar field becomes an enum when its distinct values fit the limit (8 by default, adjustable from 2 to 30), it was seen at least three times, and values repeated at least twice on average |
| Array handling | Every element is folded into one items schema: property sets are unioned, required is the intersection, and mixed element types produce a type array rather than a tuple |
| Fidelity | The sample is read by a source-faithful parser, so a 19-digit ID stays an integer instead of becoming a float, and a duplicate key is reported rather than silently dropped |
| Size, cost and processing | Up to 5 MB and 500 levels of nesting, free, no signup; inference runs in this browser tab and nothing is uploaded |
Frequently asked questions
Can a JSON Schema be inferred reliably from one sample?
No — inference describes the document you pasted, and a schema describes a contract, which is strictly more information than any single document contains. Three things in particular cannot be observed: whether a key that happens to be present is ever absent, whether the four values a status field took here are the only four it can take, and what belongs in an array that arrived empty. A generated schema is therefore a first draft that removes the tedious 90% — the nesting, the types, the property names — and leaves you the decisions. Every one of those decisions is listed under the result rather than buried in the output.
What does required actually mean — does it stop a null?
It means the key must be present, and nothing more. A property listed in required with type "string" is satisfied by "" and violated by the key being missing; a null fails on the type, not on required, and only if null is absent from the type. That is why a field the sample only ever saw as null is typed "null" here and flagged for you to widen — ['string', 'null'] is almost always what was meant. Required also says nothing about order, and JSON Schema has no way to require ordering of object keys at all.
Does format validate anything, or is it just a label?
By default it is a label. Draft 2020-12 splits format into two vocabularies, and the one in the standard dialect is Format-Annotation: a validator that supports it will note the format and still pass a value of "not-an-email". Assertion behaviour is opt-in — Ajv needs the ajv-formats package added, Python's jsonschema needs the format checker passed in explicitly. So the format keywords this generator writes are documentation until you switch assertion on, which is worth knowing before you rely on one to reject bad input.
Should I set additionalProperties to false?
It depends on which direction you are protecting. Closing an object catches typos in config keys — a misspelled retryLimit is silently ignored by an open schema and rejected by a closed one — so it is the right default for anything a human hand-writes. For an API response it usually is not: a service that adds a field in a minor release will break every client validating with a closed schema, which is why most public API schemas stay open on purpose. It also composes badly: close an object and then combine it through allOf and the result rejects the very keys the other branch introduced, because the keyword is evaluated against its own siblings alone.
Which draft is this and will my validator accept it?
Draft 2020-12, declared by the $schema line at the top. It is the current release and what Ajv understands through its 2020 build, what python-jsonschema supports as Draft202012Validator, and what OpenAPI 3.1 aligned itself with. If your tooling is on draft-07 you need three edits: 2020-12 renamed definitions to $defs, replaced the array form of items with prefixItems and gave items the job of describing every remaining element, and split dependencies into dependentRequired and dependentSchemas. Nothing else in a schema this shape changes.
Why is a field typed integer here and number in another schema?
Because integer is used only when no fractional value turned up in the sample. A quantity that reads 2, 1 and 6 becomes integer; the moment one record carries 1.5 the whole property becomes number, since a value validated against integer must have a zero fractional part. That is worth checking against reality rather than against your payload — a unit price that happened to be a round 18 in every sampled record will be typed integer and will then reject 18.50 in production. The switch in the toolbar turns the distinction off and types every number as number.
How many records should I paste for a good result?
Enough that optional fields have a chance to go missing — in practice twenty to a few hundred records of the same shape. Every element of an array is folded into one items schema, so the union of properties grows and the intersection that becomes required shrinks as you add records; with a single object the two are identical and everything looks mandatory. Beyond a few hundred the schema stops changing, and the 5 MB ceiling is far more than a representative sample ever needs.
About inferring a schema, and what a sample cannot say
Schema inference is an exercise in reading a document for what it implies rather than what it states, and the honest version of the job is knowing where implication runs out. A payload can tell you that qty held integers and that customer was an object with three keys. It cannot tell you whether backorder is optional or merely absent this time, whether the four statuses you happened to sample are the entire set, or what belongs in an array that arrived empty — an empty list says nothing at all about its contents. A field seen only as null is the sharpest example: the only defensible inference is "type": "null", which is almost certainly not the contract. Arrays are where the sample earns its keep, because folding every element into one item schema turns absence into evidence: union the property sets, intersect the ones present everywhere, and optionality becomes observable.
The output targets draft 2020-12, the release that renamed definitions to $defs, split the old array form of items into prefixItems for tuples plus items for everything after them, and reorganised the specification into vocabularies. One of those vocabularies matters here more than the rest: format is an annotation in the standard dialect, not an assertion, so a validator will happily accept an email field containing nonsense until you opt into assertion behaviour. The tuple distinction is the other honest limitation — an array whose elements differ by position and an array of mixed values look identical in one sample, so this generator writes a union of types and leaves prefixItems to you.
Underneath, the sample is read by the same source-faithful parser the rest of this site uses, which matters more for schemas than for anything else. A generator built on JSON.parse has already turned a 19-digit order ID into a float before it gets to decide between integer and number, and has already discarded one of a pair of duplicate keys without mentioning it. Here the number literal is still text at inference time and duplicates are reported. The workflow that gets the most out of this is a loop rather than a single pass: generate, tighten the points the notes raise, then take a second payload to the schema validator and see what it rejects. If the sample will not parse in the first place, the JSON checker names the character at fault.
Where your payload is read
Inference runs on your own machine: the parser and the generator are JavaScript in this tab, and no part of the sample is uploaded, cached or logged. Since a representative payload is by definition real production data — real emails, real order numbers — that is the only arrangement that makes pasting one here reasonable.