JSON Schema Generator_

Paste a JSON document and get a JSON Schema for it, in draft 2020-12 or draft-07. Paste several samples instead and it works out which fields are optional, rather than marking every one required because it only ever saw one example.

Inference is guesswork, so every guess is labelled. When a field is required only because there was one sample, when an array was always empty, when two samples disagreed about a shape — the schema says so underneath instead of looking more certain than it is.

toolkit.codes/json-schema-generator
Sample
Paste a JSON document to begin
UTF-8
Ready
100% LOCAL
Input
One JSON document, or an array of documents treated as repeated samples of the same thing.
Output
A JSON Schema, plus a note for each place where something had to be assumed.
Processing
Every sample is observed before any schema is written, so a decision from the first document can still be revised by the fifth.
Limits
A schema inferred from examples describes the examples. It cannot know that a field you never saw empty is allowed to be, or that the three values you saw are the only three.
Why several samples matter
From one document every key looks required and every array looks homogeneous. Optionality is a fact about a set of documents, not about one, and nothing can recover it from a single example.

A schema inferred from one example is mostly a guess

Everything looks required until it does not

Given {"id": 1, "nickname": "ada"}, is nickname required? Nothing in that document answers the question. Every generator has to pick, and marking everything required is the usual choice because it is the safe-looking one — it just happens to reject valid data the moment a record omits an optional field. Paste three or four records with the top-level array set to "many samples" and the answer stops being a preference: a key present in every sample is required, and a key missing from any of them is not.

An empty array teaches nothing

"tags": [] tells you the field is an array and stops there. Most tools quietly emit items: {"type": "string"} anyway, and the schema then rejects the first record with a number in it. Here the array is left open and a note says why, which is less satisfying and more accurate. The same applies to a field that was null in every sample: its type is "null", because that is genuinely all that was observed.

Arrays are merged, not sampled

An item schema taken from the first element is wrong whenever the array is mixed, and mixed arrays are common in real data. Every element is observed here and the results combined: two primitive types become a type union, an object next to a number becomes anyOf, and objects with different keys merge into one shape whose required list is the intersection. That is more work than reading element zero and it is the difference between a schema that validates your data and one that validates your first row.

The draft you name changes the syntax

Draft 2020-12 is current and is the default here. Its most consequential break from draft-07 is that tuple validation moved: items used to accept an array to describe positional elements, and now means "every element", with prefixItems taking the tuple role. A generator that writes draft-07 shapes under a 2020-12 $schema produces something that validates differently from how it reads, and nothing warns you. Switching the draft here switches the syntax as well as the URL.

Paste, choose how strict, take the schema

  1. 01Paste one JSON document. The schema appears immediately, with notes underneath for anything that had to be assumed.
  2. 02Have several records? Paste them as a JSON array and tick "Top-level array is many samples" — that is what turns required from a guess into a measurement.
  3. 03Tighten or loosen with the switches. "No extra properties" closes every object; "Detect enums" turns small repeated string sets into an enum, which is off by default because it is the guessiest thing here.
  4. 04Test it: paste another record into the box at the bottom and it will tell you which fields fail and where.

Four things people generate a schema for

Validating an API response in tests

You have a recorded response and want a contract from it.

Paste
several recorded responses
Get
a schema with real optionality

Documenting a config file

Editors offer completion when a config has a schema.

Add
"$schema" to the config
Result
autocomplete and inline errors

Constraining a model’s output

Structured output needs a strict schema.

Switch on
No extra properties
Get
additionalProperties: false throughout

Finding out why a record was rejected

One record fails and the message is unhelpful.

Paste it
into the test box
Get
the exact path that failed

What is inferred, and how confident it is

ObservedEmittedHow much of a guess
A whole number"type": "integer"Safe until a fractional value appears, then the field widens to number
A key in every samplerequiredA measurement with several samples; a pure assumption with one
A key missing from any sampleLeft optionalReliable — absence is evidence
A null beside a string["string", "null"]Reliable
A null in every sample"type": "null"Literal. It is all that was seen, and probably not what you meant
An empty array"type": "array", no itemsDeliberately silent — guessing the item type is how schemas reject valid data
A mixed arrayanyOf, or a type unionReliable, because every element was merged rather than sampled
A date-shaped string"format": "date"Advisory. JSON Schema does not require validators to enforce format
A few repeated stringsenumThe guessiest thing here, which is why it is off by default

Everything in the last column appears as a note under the schema as well, against the path it applies to, so nothing has to be remembered from this table.

What changed between draft-07 and 2020-12

Concerndraft-072020-12
Tuple itemsitems: [A, B]prefixItems: [A, B]
Every elementitems: Aitems: A — same spelling, and now the only meaning
Extra tuple elementsadditionalItemsitems takes that role
Identifier$id with a trailing # by convention$id without one
Reusable definitionsdefinitions$defs
$schema URLhttp://json-schema.org/draft-07/schema#https://json-schema.org/draft/2020-12/schema

This generator emits neither prefixItems nor definitions, because inference from examples never produces a tuple or a shared definition. The distinction matters when you hand-edit the result.

Getting a schema you can trust

  • Paste as many real records as you can, as an array, with "many samples" ticked. Nothing else improves the result as much, and it is the only way to learn which fields are optional.
  • Include the awkward records deliberately — the one with the null, the one missing a field, the one with an empty list. A schema built only from tidy examples rejects the untidy ones.
  • Leave enum detection off unless you genuinely know the set is closed. Three repeated values in a sample of four are not evidence of a constraint.
  • Turn on "No extra properties" for structured model output and leave it off for an API contract, where a server adding a field should not break your client.
  • Treat format as documentation. The specification makes it advisory by default, so a validator may accept a malformed email that your schema calls an email.
  • Run the result past the test box with a record you know is bad, not just one you know is good — a schema that accepts everything passes the happy path too.

What an inferred schema cannot know

It describes your examples, not your data model

If no sample had an empty string, nothing forbids one. If every id happened to be positive, no minimum is emitted. Inference can only narrow to what it saw, and what it saw is a sample rather than the specification. Treat the output as a first draft to edit, not a finished contract.

One sample makes everything required

That is stated in a note whenever it happens, because it is the single most misleading thing a generator does silently. A schema that marks an optional field required will reject perfectly good records, and it will do it in production rather than in the test that generated it.

format is advisory unless you opt in

JSON Schema says validators are not required to enforce format, and many do not by default. A schema that annotates a field as an email is documentation until you turn on format assertion in whichever validator you use. Do not rely on it for input validation.

The test box is not a JSON Schema validator

It understands the subset this generator emits — type, properties, required, items, enum and anyOf — and nothing else. That is enough to check a record against the schema above and is not a general validator. For a schema you have hand-edited, use a real implementation.

A top-level array is genuinely ambiguous

It might be the data — an array is a perfectly good document — or it might be a list of examples of one thing. The switch decides, and getting it wrong produces a valid schema for entirely the wrong shape. There is no way to infer which you meant.

How the inference works

Two passes
Every sample is observed into an intermediate structure before any schema is written, so a conclusion drawn from the first document can still be revised by the fifth. Writing as it goes would make the first record authoritative
Required
A key is required when it appeared in every object seen at that position. With one sample that is every key, and a note says so against the path
Numbers
integer until a fractional value appears anywhere in the field, at which point the whole field becomes number with a note. A field is not an integer that sometimes is not
Arrays
Item schemas are merged across every element of every array, never taken from the first. Disagreement between kinds produces anyOf; disagreement between primitives produces a type union
Formats
date-time, date, time, uuid, email, ipv4 and uri, all registered by the specification. Applied only when every observed value of the field matches the same one — inventing format names would produce schemas no validator understands
Enums
Off by default. When on, a string field qualifies at six or fewer distinct values across at least three samples, and the values are sorted so the same data always yields the same schema
Draft
2020-12 by default with the https identifier; draft-07 available. Neither prefixItems nor definitions is emitted, because inference from examples produces no tuples and no shared definitions
Limits
Distinct string values are tracked to 200 per field before enum detection gives up on it, so a large document cannot grow the working set without bound
Scope
Inference and a subset validator. Formatting and validating JSON itself belong to the JSON formatter, and querying it to the JSONPath tester
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 a JSON Schema

How do I create a JSON Schema from JSON?

Paste the document above and the schema appears immediately. For a schema worth trusting, paste several real records as a JSON array and tick "Top-level array is many samples" — that is what lets it tell required fields from optional ones instead of marking everything required.

Why is every field marked required?

Because you gave it one sample, and a single document contains no evidence about optionality. A note under the schema says so whenever it happens. Add more records, or turn off "Infer required" and add the required list by hand.

Which draft should I use?

2020-12 unless something in your toolchain needs otherwise — it is the current one and what most modern validators default to. The switch changes the syntax as well as the $schema URL, which matters because the meaning of items differs between the two and a mismatch validates differently from how it reads.

Why is my empty array not given an item type?

Because nothing can be known about it. Most generators emit a string item type anyway, and the schema then rejects the first record containing a number. Leaving it open is less satisfying and more accurate; a note under the schema points at the path so you can fill it in yourself.

Will the format annotations be enforced?

Only if your validator is configured to. The specification treats format as advisory by default and many implementations ignore it unless asked. Useful as documentation and for editor hints; not something to rely on for input validation.

Can I use this for structured model output?

Yes, and switch on "No extra properties" when you do — providers that constrain output to a schema generally require every object to be closed. Check the result against a real record with the test box before wiring it in.

Is my JSON uploaded 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.