JSON Schema Validator

Check JSON, YAML or JSON Lines against a JSON Schema from draft-04 to 2020-12. Errors link to the data line and schema keyword. Runs in your browser, no upload.

  • Runs in your browser
  • Your data never leaves your browser
  • Free · No Sign-Up
Auto reads $schema and uses Draft 2020-12 when it is absent. The menu overrides $schema. Only this menu and Check format are saved; schema and data are not stored.
Check format validates supported formats such as email, date and uuid. Turn it off to treat format as an annotation. Unrecognized formats are listed in the notes.
Typing validates after 300 ms. When the three inputs total more than 1,000,000 UTF-16 code units, press Validate or Ctrl/⌘+Enter. Cancel stops a running validation.

Paste a schema and data. The result updates as you type.

Paste JSON or YAML, open a file, or drop it on this box. Files up to 20 MiB are accepted. The examples menu replaces both inputs and any referenced schemas, then validates them.
Paste JSON, YAML, JSON Lines or multiple YAML documents separated by ---. Each document is validated on its own. Open a file or drop it on this box; the file limit is 20 MiB.
Paste each referenced schema with its $id. Separate schemas with a line containing only ---. The tool never downloads $ref URLs.
Referenced schemas ($ref targets)

Paste schemas that your $ref points to, each with its "$id". Separate several with a line containing only ---. Nothing is downloaded.

Validation errors and notes appear here.

Read the full guide JSON Schema: Drafts, Core Keywords, and How Validators Really Differ
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.

Example: the product schema from json-schema.org

The JSON Schema getting started guide builds a product schema step by step. Its last version points to a second file with "$ref": "https://example.com/geographical-location.schema.json". Paste that schema and a product with four mistakes, and the tool stops before checking the data:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/product.schema.json",
  "title": "Product",
  "type": "object",
  "properties": {
    "productId": { "type": "integer" },
    "productName": { "type": "string" },
    "price": { "type": "number", "exclusiveMinimum": 0 },
    "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true },
    "dimensions": {
      "type": "object",
      "properties": { "length": { "type": "number" }, "width": { "type": "number" }, "height": { "type": "number" } },
      "required": ["length", "width", "height"]
    },
    "warehouseLocation": { "$ref": "https://example.com/geographical-location.schema.json" }
  },
  "required": ["productId", "productName", "price"]
}
{
  "productId": 1,
  "productName": "A green door",
  "price": 0,
  "tags": ["home", "green", "home"],
  "dimensions": { "length": 7.0, "width": 12.0 },
  "warehouseLocation": { "latitude": 91, "longitude": -122.4 }
}
The schema cannot be used (Draft 2020-12):
$ref "https://example.com/geographical-location.schema.json" at #/properties/warehouseLocation/$ref cannot be resolved. URLs are not downloaded: paste that schema under Referenced schemas with "$id": "https://example.com/geographical-location.schema.json".

The tool does not download the URL. Paste the guide’s geographical-location schema under Referenced schemas instead:

{
  "$id": "https://example.com/geographical-location.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["latitude", "longitude"],
  "properties": {
    "latitude": { "type": "number", "minimum": -90, "maximum": 90 },
    "longitude": { "type": "number", "minimum": -180, "maximum": 180 }
  }
}

Now all four mistakes are reported, in the order they appear in the data, each with its line:

4 errors at 4 locations (Draft 2020-12).
/price (line 4, column 12): must be > 0, but is 0  schema #/properties/price/exclusiveMinimum
/tags (line 5, column 11): items 0 and 2 are equal (uniqueItems)  schema #/properties/tags/uniqueItems
/dimensions (line 6, column 17): missing required property "height"  schema #/properties/dimensions/required
/warehouseLocation/latitude (line 7, column 38): must be ≤ 90, but is 91  schema https://example.com/geographical-location.schema.json#/properties/latitude/maximum

The error inside the referenced file shows that file’s $id in the schema path, so you know which file to fix.

Example: a schema copied from an OpenAPI 3.0 document

OpenAPI 3.0 schemas often contain nullable and put description or maxLength next to $ref. Pasted into a draft-07 validator, both behave differently from what the author meant. Draft-07 says other keywords in a $ref object must be ignored, and nullable is not a JSON Schema keyword at all:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": { "code": { "type": "string" } },
  "type": "object",
  "properties": {
    "code": { "$ref": "#/definitions/code", "maxLength": 3 },
    "nickname": { "type": "string", "nullable": true }
  }
}
{ "code": "ABCDEF", "nickname": null }
1 error (Draft 7).
/nickname (line 1, column 33): must be string, but is null  schema #/properties/nickname/type
* In Draft 7, keywords next to "$ref" are ignored: "maxLength" at #/properties/code.
* "nullable" at #/properties/nickname is an OpenAPI 3.0 keyword, not JSON Schema, and is ignored. Use "type": ["string", "null"].

Python jsonschema 4.26.0 gives the same answer: code passes (the maxLength is ignored) and nickname: null fails. Plain Ajv, which most browser validators use, reports the opposite on both fields. This tool removes the keywords Ajv applies outside the specification and tells you about each one, so the result matches the specification and the note tells you what to change.

Example: one bad line in a JSON Lines export

Paste one JSON value per line and each line is validated on its own. The result names the line:

{ "type": "object", "required": ["id", "event"], "properties": { "id": { "type": "integer" }, "event": { "enum": ["signup", "login", "logout"] } } }
{"id": 1, "event": "signup"}
{"id": 2, "event": "log-in"}
{"id": 3}
2 of 3 documents have errors (Draft 2020-12).
Document 1 (line 1): valid
Document 2 (line 2)
  /event (line 2, column 20): must be one of "signup", "login", "logout"  schema #/properties/event/enum
Document 3 (line 3)
  (root) (line 3, column 1): missing required property "event"  schema #/required
* The data is read as JSON Lines: 3 lines, each validated on its own.
* No $schema: validated as Draft 2020-12. Add "$schema" or pick a draft in the menu.

When the result is “Cannot be determined”

Ajv passes most of the official test suite, but it gets a few constructs wrong. For those inputs the tool gives no valid / invalid result: the status says Cannot be determined, the reasons are listed, and the copied text and JSON say the same ("state": "unknown", "valid": null). A recursive tree schema that uses $dynamicRef, the 2020-12 keyword for extensible recursion, is one case:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$dynamicAnchor": "node",
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "children": { "type": "array", "items": { "$dynamicRef": "#node" } }
  }
}
{ "name": "root", "children": [{ "name": 1 }] }
Cannot be determined (Draft 2020-12): this input reaches a case the validator cannot check reliably, so no valid / invalid result is given. Reasons below.
Cannot be determined, because:
- "$dynamicRef" at #/properties/children/items/$dynamicRef: Ajv implements dynamic references only in part and gives wrong results on some official test cases.

If you do not extend the schema from another one, "$ref": "#" means the same here and the tool can check it. The other cases are $recursiveRef whose first target has no "$recursiveAnchor": true, nested $id with relative $ref (Ajv runs out of stack), unevaluatedItems / unevaluatedProperties together with contains, an if without both then and else, or items inside an anyOf / oneOf branch, a meta-schema whose $vocabulary adds or leaves out vocabularies, a property named __proto__ that the data uses, and numbers that JavaScript cannot hold exactly (next section). In JSON Lines and multi-document YAML each document gets its own state: one invalid document makes the result invalid; otherwise one undetermined document makes it undetermined.

How errors are grouped

Ajv, the validator this tool runs, reports every failed branch of a oneOf or anyOf. For a payment that is either a card or a bank account, a card with a two-digit last4 produces five Ajv errors: the two real problems, three complaints from the bank branch, and the summary. This tool shows one error at /payment and opens the closest branch, the one with the fewest errors, not counting a branch whose const discriminator ("method": "bank") already fails. The other branches stay folded. The same works when each branch is a $ref. An if / then failure is shown as the then error with “via then”.

Which draft is used

$schemaDraft
http://json-schema.org/draft-04/schema#Draft 4
http://json-schema.org/draft-06/schema#Draft 6
http://json-schema.org/draft-07/schema#Draft 7
https://json-schema.org/draft/2019-09/schema2019-09
https://json-schema.org/draft/2020-12/schema2020-12
missing or another URI2020-12, with a note

The tool also reads https://json-schema.org/draft-07/schema and other http / https variants, with a note that some validators do not. Draft-07 array items in a schema without $schema makes the schema invalid under 2020-12; the error says to use prefixItems or pick Draft 7.

Compared with other online validators

We ran the same six inputs through the first results for “json schema validator” on Bing on 2026-10-02: a draft-07 $ref with maxLength next to it, "required": ["constructor"] against {}, nullable with null, 9007199254740993 against "maximum": 9007199254740992, a 2020-12 prefixItems schema, and YAML data.

ValidatorUpload$ref siblingconstructornullable2^532020-12YAML
jsonschemavalidator.netyes, schema and data to /api/jsonschema/validateignoredfailsfailspasses, no warningcorrectno
jsonlint.comnoappliedpassespassespasses, no warningcorrectno
ZeroToolnoignored, notefailsfails, notecannot be determined, notecorrectyes

The correct answers are: ignored, fails, fails, fails. No browser-side validator can get the 2^53 case right, because JSON.parse turns both numbers into 9007199254740992 before validation. This tool names the changed number and gives no verdict for it.

Limits

  • The validator is Ajv 8.18 with ajv-formats 3.0.1 and ajv-draft-04 1.0.0. On the required tests of the official JSON Schema Test Suite the tool gives the expected result for 616 of 618 draft-04 tests, 839 of 841 draft-06, 927 of 929 draft-07, 1,230 of 1,261 for 2019-09 and 1,210 of 1,301 for 2020-12, and says “Cannot be determined” for the rest (2, 2, 2, 31 and 91 tests); no test gets a wrong result. The rules look only at the schema and the data, so they also cover some tests Ajv would have passed: every $dynamicRef schema, for example.
  • $ref to a URL is never fetched. Paste the referenced schema, with its $id, under Referenced schemas.
  • Numbers are read with JSON.parse. A number that a JavaScript double cannot hold exactly, such as 9007199254740993, 1.0000000000000001 or 1e400, gets a note with its line (0.1 and 1.0 are fine). When the schema compares numbers (type, minimum, maximum, multipleOf, const, enum, uniqueItems), that document is “Cannot be determined”. Such a number in the schema, or any such number in YAML data, makes the result “Cannot be determined” in every case. multipleOf is checked on the decimal values, so 19.99 is a multiple of 0.01 and 0.3 is a multiple of 0.1 (dividing the doubles, as Ajv does, says they are not). Duplicate keys keep the last value and get a note.
  • Line numbers are shown for JSON and JSON Lines. YAML errors show the path only.
  • Inputs over 1 MB are checked when you press Validate; files over 20 MB are refused. Validation runs in a Web Worker, so the page keeps responding; Cancel stops a long run. A 6 MB array of 40,000 records took about 2 seconds in our test, with no main-thread task of 50 ms or more while it ran (putting a 6 MB file into the text box is the slow part).
  • pattern is an ECMA-262 regular expression with the u flag. \d matches only ASCII digits, so Python re (where \d also matches 123) can disagree.

Related tools: generate a first schema from a sample with JSON to JSON Schema, check YAML syntax with the YAML Validator, and validate a whole API description with the OpenAPI Validator.

FAQ

Which JSON Schema drafts are supported?

Draft-04, draft-06, draft-07, 2019-09 and 2020-12. The tool reads the draft from $schema. A schema without $schema is checked as 2020-12, the same default as Python jsonschema and Go santhosh-tekuri/jsonschema. Pick a draft in the menu to override $schema; the tool then shows a note that the two differ.

Is my data uploaded?

No. The schema and data are checked by Ajv inside your browser tab, and the tool makes no network requests with them. It also never downloads a schema that a $ref points to: paste that schema under Referenced schemas. Only the draft menu and the Check format switch are saved in your browser.

Does it check format (email, date, uuid)?

Yes, while Check format is on (the default): email, uri, uri-reference, uri-template, date, time, date-time, duration, hostname, ipv4, ipv6, uuid, json-pointer, relative-json-pointer and regex, through ajv-formats. Other formats, such as idn-email or iri, pass and are listed in a note. Turn the switch off to treat format as an annotation, which is the default of the 2020-12 specification and of Python jsonschema.

Why does my schema pass here and fail in another validator?

Usually the draft, format checking or a keyword the draft does not have. The notes under the result list what this tool ignored: unknown keywords (with a suggestion for typos), keywords next to $ref in draft 4–7, nullable from OpenAPI 3.0, and formats it does not check. Another cause is a number such as 9007199254740993 that JavaScript cannot hold exactly; when the schema compares numbers, this tool says "Cannot be determined" instead of giving a result.

Can I validate a JSON array or many records at once?

Yes. Any JSON value can be the root, including an array. For many records, paste JSON Lines (one JSON value per line) or YAML documents separated by ---; each document is validated on its own and the result lists the ones with errors.