Tools · JSON Schema

JSON to JSON Schema

Paste a JSON document and get a draft 2020-12 schema that describes it — each key typed from the value it holds, arrays from their items, nothing invented. It runs in your browser; the document never leaves the tab.

no signup · runs entirely in your browser · ⌘V works anywhere on this page

What you get

  • Describes the API-response sample as draft 2020-12 · 34 properties · 7 objects
  • Nests the schema the way the document nests: each object with its properties and its required list, each array with its items
  • Writes format: date-time on a string only when every value seen is an RFC 3339 date-time, and integer only when every number seen was written whole — 149 is one, 149.00 is not
  • Leaves a key out of required when some elements lack it: the paginated list's charges drop failure_message from required, because two of three charges lack it
  • Types a field that is only ever null as ["string", "null"] — the one guess it makes, said here and in the reference

What it will not do

  • Invent titles, descriptions, enums, minimums or patterns. It types what is there.
  • Write $defs or $ref. The schema is nested like the document; a shape used twice appears twice.
  • Validate anything against the schema — paste it into the validator you already use.
  • Send your text anywhere. The page is static and the engine runs in this tab — open the network panel and watch it stay empty.

What you get

An object → type, properties, required
{"id": 1, "status": "paid"}{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "integer" }, "status": { "type": "string" } }, "required": ["id", "status"] }
A key missing in some items → not required
[{"id":1,"note":"x"},{"id":2}]{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "note": { "type": "string" } }, "required": ["id"] } }
An RFC 3339 string → format: date-time
{"created_at": "2026-04-21T14:32:08Z"}{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "created_at": { "type": "string", "format": "date-time" } }, "required": ["created_at"] }
A number written whole → integer; written with a point → number
{"qty": 2, "price": 12.50, "total": 149.00}{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "qty": { "type": "integer" }, "price": { "type": "number" }, "total": { "type": "number" } }, "required": ["qty", "price", "total"] }

149.00 parses to 149, so the value alone would say integer; the schema reads the number as you wrote it.

null → a nullable string, the one guess
{"line2": null}{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "line2": { "type": ["string", "null"] } }, "required": ["line2"] }

A null alone says nothing about the value; a schema that accepts only null is useless.

The sample

What the first sample opens — a real file, not an illustration written for this page.

clean-order-example.json → JSON Schema, as Convert writes it — draft 2020-12 · 34 properties · 7 objects · 2.3 kb
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "order_id": { "type": "string" },
    "created_at": { "type": "string", "format": "date-time" },
    "status": { "type": "string" },
    "customer": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "email": { "type": "string" },
…

in VS Code

Convert, then JSON Schema — from a document or a selection, into a new editor.

unstringify for VS Code14-day trial · Free and Pro

Questions

Which draft is it?

Draft 2020-12, named in $schema. Every keyword it writes — type, properties, required, items, format — reads the same in draft-07, so an older validator takes it too.

Why is a field required when my API sometimes omits it?

The schema describes the sample: a key present on every element is required. Paste a response that omits the field, or a list where some elements lack it, and it leaves required.

What happens when a field is only ever null?

It is typed ["string", "null"]. A lone null says nothing about the value, so this is the one place the schema guesses — and it guesses string.

Try it on the file that broke your afternoon.

free · no signup