JSON Schema Generator
Paste sample JSON, get a JSON Schema in the draft you target — required derived from what the samples actually show, entirely on this device.
Inferred from what the samples show: a key missing from one sample drops out of required, and an empty array has no item type. No minLength, pattern or numeric ranges are ever guessed.
Names the top-level definition. Letters, digits, underscore and single spaces are kept; anything else is dropped, and quicktype re-cases the result into its own identifier.
Closed writes additionalProperties: false on every object, so anything the samples never showed is rejected. Open leaves the line out, so unseen keys are allowed.
Off by default. On, RFC 3339 date-times and RFC 9562 UUIDs are annotated with format. URL-shaped strings get format: uri regardless — quicktype detects URIs outside this switch.
Off by default. On, quicktype may turn a small repeated value set into an enum. It is a heuristic: two distinct values repeated twice do not trip it, roughly ten-plus observations do — the switch permits the guess, it cannot force it.
The JSON Schema appears here as you type.
Press ? for shortcuts
Do it offline:$ npx quicktype sample.json --lang schema --top-level Root -o schema.json
How to use it
- Drop a .json file onto the input pane, or paste a response into it; the schema rebuilds as you type.
- Open one tab per payload you have, up to ten — an extra tab can only take keys out of required, never put them in.
- Choose the target draft, name the root definition, and say whether properties the samples never showed are allowed.
- Copy the schema, save it as schema.json, or share a link that reopens the same tabs with the same switches.
Paste sample JSON and get a JSON Schema: property types, nested objects lifted into named definitions and reached by $ref, and a required list narrowed by every extra payload you add. Read the samples as evidence, not truth — no minLength, pattern or range is ever guessed from them. Emit 2020-12, draft-07 or draft-06. Nothing is uploaded.
Examples
{"id":1,"email":"ada@example.com","nickname":"ada"}
{"id":2,"email":"grace@example.com"}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$ref": "#/$defs/Root",
"$defs": {
"Root": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "integer"
},
"email": {
"type": "string"
},
"nickname": {
"type": "string"
}
},
"required": [
"email",
"id"
],
"title": "Root"
}
}
}Two payloads, one schema. nickname keeps its string type because the first tab showed one, but it drops out of required because the second tab did not carry it — that subtraction is the whole reason to paste more than one sample.
{"id":1,"author":{"name":"Ada","id":7}}{
"$schema": "http://json-schema.org/draft-06/schema#",
"$ref": "#/definitions/Root",
"definitions": {
"Root": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "integer"
},
"author": {
"$ref": "#/definitions/Author"
}
},
"required": [
"author",
"id"
],
"title": "Root"
},
"Author": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "integer"
}
},
"required": [
"id",
"name"
],
"title": "Author"
}
}
}The nested object becomes its own entry rather than an inline block, so a shape used twice is written once. On draft-06 the container is definitions and pointers read #/definitions/…; on 2020-12 those become $defs and #/$defs/….
{"id":"0b5b8e6c-6a1d-4c2e-9b3a-5f6d7e8c9a0b","at":"2026-08-11T09:15:00Z"}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$ref": "#/$defs/Root",
"$defs": {
"Root": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"at",
"id"
],
"title": "Root"
}
}
}Format detection is off until you ask for it, and reads the characters rather than the key: a field called at holding "yesterday" stays a plain string. format is an annotation — many validators assert it only when told to.
{"tags":[],"nickname":null}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$ref": "#/$defs/Root",
"$defs": {
"Root": {
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": {}
},
"nickname": {
"type": "null"
}
},
"required": [
"nickname",
"tags"
],
"title": "Root"
}
}
}The edge case worth meeting early: an empty array carries no item type, so items is left open, and a field seen only as null gets the type "null". Both are placeholders to replace by hand. Open additional properties also removes the additionalProperties line.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
required is the intersection, never the union
A key lands in required only when every sampled object of that shape carried it. One payload therefore produces a maximally strict list, and each tab you add can only shorten it. If your API omits a field on some responses, paste one of those responses.
integer widens to number and stays there
A value of 1 alone is typed integer. Show 2.5 for the same key in another tab and the type becomes number for good — there is no union of the two, because every integer already validates as a number. JSON itself draws no line between them.
What the draft switch actually changes
Three positions and nothing else: the $schema URI, the name of the root container, and the prefix on internal pointers. draft-06 and draft-07 keep definitions; 2020-12 renames it to $defs and rewrites each pointer to match. Your property names and values are never touched, even when a key is literally called $ref.
Nothing is invented about values
No minLength, maxLength, pattern, minimum, maximum, multipleOf or uniqueItems is ever emitted, because a sample cannot justify one. A URL-shaped string is the one loud exception: format "uri" plus quicktype's own qt-uri-protocols key arrive whether or not format detection is on. Delete that key if your validator rejects unknown vocabulary.
Common errors
Sample 2: Unexpected '"' at line 1, column 10 — probable cause: missing comma between properties.- Every tab has to parse before any of them is read for shapes. The Sample prefix names the failing tab and appears only when more than one is open; the caret frame marks the character, and Jump to error moves the cursor onto it.
Input is larger than the 10 MB limit for this tool.- Past the combined-sample ceiling the run is refused outright, never quietly trimmed: a truncated payload would describe a document that does not exist. Ten representative records teach the shape that ten thousand identical ones do.
duplicate key `id` at lines 2 and 3 — most parsers keep the last- A warning, not a refusal. JSON permits repeated keys and most parsers keep the final one, so the schema describes that winner — worth knowing before you trust the result as a picture of the file you pasted.
Root.nickname is optional — some sampled objects did not carry it, so it stays out of required- One chip per narrowed key, listed under the output. It is the audit trail for the required list: if a key you expected to be mandatory shows up here, one of your tabs is missing it.
Root.tags was an empty array in every sample — no item type is knowable, so items stays open- An empty array is evidence of an array and of nothing further, so items is left as the always-true empty schema rather than guessed. Paste a payload with one element and the entry fills itself in.
FAQ
Which draft should I choose?
2020-12 unless something downstream pins you earlier — it is the current release and the default here. Pick draft-07 for tooling that stopped there, and draft-06 for quicktype's own dialect, which nothing here rewrites.
Why does required list the keys in a different order from properties?
Because quicktype sorts required alphabetically while properties keeps the order the keys first appeared in. Both orders are meaningless to a validator, so neither is corrected here — the output you see is what the generator really emitted.
Is the result strict enough to police production traffic?
Not on its own. It pins types, required keys and, by default, rejects unknown properties, but it says nothing about lengths, numeric ranges or string patterns. Treat it as the skeleton you then tighten by hand against the rules your service actually has.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the generator again — how a large paste starts.
- ⌘/Ctrl + S
- Write schema.json to disk instead of saving the page.
- ⌘/Ctrl + C
- With no selection active, copies the whole schema.
- ⌘/Ctrl + Shift + C
- Copy the schema even while text is selected.
- t
- Switch the theme, unless the caret is in a text field.
- ? or ⌘/Ctrl + /
- Open the shortcut list.
- Esc
- Close whichever overlay is on top.