Skip to content
DevPenh

JSON to JSON Schema

Paste sample JSON to get a JSON Schema that describes it: the type of every value, which keys are required, which can be null, and one merged schema for the items of each array. The output uses draft 2020-12 by default, or draft-07 for older validators. Then check another document against the generated schema, or against a schema you paste, and see each error with its path.

Draft
Required

Paste JSON or load the example to get started.

Validate JSON against this schema

Validate with

Paste a JSON document to check it against the generated schema.

How to use it

  1. Paste a JSON document, such as an API response. For a list endpoint, paste an array with several items: the more variety the sample has, the better the schema.
  2. Pick the draft your validator supports and the options you need. The schema updates as you type.
  3. Copy the schema, then review it. It describes the sample, not the API's contract, so tighten or loosen it where you know better.
  4. To check another response, paste it into Document to validate. Choose My schema to edit the generated schema or paste your own before validating.

How types are chosen

JSON valueSchema
"text"{"type": "string"}
42, -7{"type": "integer"}
4.5, 1.0, 1e3{"type": "number"}
true / false{"type": "boolean"}
null only{"type": "null"}
An object"type": "object" with properties and required
An array"type": "array" with one items schema built from all of its items
[]{"type": "array", "items": {}}, which allows any item

Inference rules

  • Numbers are read from the text. 1 is an integer; 1.0 and 1e3 are a number, even though JavaScript parses both to the same value as 1. If one location holds both, the schema says number, which accepts integers too.
  • Every array item is used. For an array of objects, the keys of all items are merged into one properties list, in the order they first appear.
  • required lists the keys present in every sample object. A key that some items leave out is optional. A key that is present but null is still required, and its type includes "null", for example "type": ["string", "null"]. Choose Required: None to leave required out.
  • Mixed values get a list of types. If one location holds a string in one sample and an object in another, the schema says "type": ["object", "string"] and keeps the object's properties next to it. The object keywords only apply to objects, so strings still pass. The tool does not use anyOf.
  • No extra keys adds "additionalProperties": false to every object that has keys, so a key outside the sample is rejected. Objects that are always empty ({}) are left open, because an empty sample says nothing about which keys are allowed.
  • Detect string formats is off by default. When it is on, format is added only if every string at that location matches the same strict pattern: date-time (RFC 3339 with T and an offset, such as 2026-11-04T09:30:00Z), date (a real calendar date, 2024-02-29), uuid, email (a domain with at least one dot) or uri (absolute http or https URLs only). Anything else, including 2026-11-04 09:30:00 with a space, gets no format. uuid is not emitted for draft-07, which does not define it.
  • Include examples copies up to three distinct values per field into examples. Leave it off if the sample contains real customer data you do not want in a schema file.

Validating a document on this page

The validation panel uses @cfworker/json-schema 4.1.4 (MIT). It reads the schema directly instead of compiling it to JavaScript code, so it runs under this site's strict Content Security Policy. It supports drafts 4, 7, 2019-09 and 2020-12; the draft is taken from the schema's $schema, and a schema without one is read as 2020-12 (draft-06 is read as draft-07). Every problem is listed, up to 100, with the path of the failing value (such as $[0].tags[1]), the keyword that failed and a short message. A rejected extra key is shown at the key itself; for anyOf, oneOf and not only the combined failure is shown.

  • format is always checked for the formats the library knows, including date-time, date, time, email, uri, uuid, ipv4, ipv6 and hostname. Draft 2020-12 treats format as an annotation by default, so a strict 2020-12 validator may accept a value this panel rejects. Unknown formats are ignored. The library's patterns are its own, so they can accept values the generator would not label (it allows a space in date-time, for example).
  • $ref must point inside the schema. Remote schemas are never downloaded, so a $ref to another URL is reported as an error.
  • The library documents a few unsupported parts of the official test suite, including $dynamicRef, $vocabulary, some unevaluatedProperties and unevaluatedItems edge cases, and internationalised email and host-name formats.
  • Before validating, the schema gets a basic structure check (for example, "type": "strin" or a pattern that is not a valid regular expression). It is not a full check against the draft's meta-schema.
  • Validation runs on the page as you type. A very slow pattern in a schema you paste can freeze the tab, and extremely deep documents are reported as too deeply nested rather than validated.

Validating with the schema in Node.js

In Node.js, Ajv validates draft 2020-12 schemas with its ajv/dist/2020 build, and the ajv-formats package adds the format checks. Save the schema as schema.json and run:

import Ajv2020 from "ajv/dist/2020.js";
import addFormats from "ajv-formats";
import schema from "./schema.json" with { type: "json" };

const ajv = new Ajv2020({ allowUnionTypes: true });
addFormats(ajv);
const validate = ajv.compile(schema);

const data = [{ id: 1, email: "not-an-email", v: [] }];
if (!validate(data)) console.log(validate.errors);

Ajv's strict mode prints a warning for a list of types such as ["integer", "string"] unless allowUnionTypes is set; a type plus "null" needs no option. For a draft-07 schema, import Ajv from ajv instead. This snippet was run on Node.js 24.21 with Ajv 8.20.0 and ajv-formats 3.0.1. To find what changed between two responses rather than whether one is valid, use JSON Diff.

Limitations

  • The schema can only describe what the sample shows. A field that is never null or never missing in your sample becomes required and non-nullable, even if the API sometimes omits it.
  • No value constraints are guessed: no enum, minimum, maxLength, pattern or minItems. Add them by hand where you know the rules.
  • Arrays always get a single items schema. Tuples (fixed positions with different types) are not detected.
  • Objects with the same structure in different places are written out in full each time; the tool does not create $defs or $ref.
  • A key repeated inside one object keeps its last value, as JSON.parse does.

Checked on 2026-11-04: schemas generated from 22 test documents (nested objects, arrays of objects with missing keys, nulls, mixed integers and decimals, empty arrays, top-level arrays and primitives, Unicode keys, 60 levels of nesting) with all 32 combinations of the options compiled in Ajv 8.20.0 strict mode, each document validated against its own schema, and documents with a wrong type, a missing required key, an extra key or a broken format were rejected.

Pasting a Flutter log or invalid JSON

A map printed by Dart's print, such as {id: 1, name: Ada}, is not JSON. Use Try to repair to convert it first, then check the guessed types. The JSON Formatter shows the exact position of other errors, and common JSON errors explains how to fix them. To get Dart classes from the same JSON instead, use JSON to Dart.