JSON Toolkit

draft-07 or 2020-12

Bottom line: 2020-12 is current and adds $defs, prefixItems and unevaluatedProperties, but many tools still speak draft-07 only. Choose by what your whole toolchain supports.

Advanced~4 min readPublished 2026-10-30Updated 2026-10-30
Differences between JSON Schema drafts and how to choose

Bottom line: use 2020-12 for new projects, fall back to draft-07 the moment any validator, code generator or OpenAPI tool only supports it, and always pin the draft with $schema.

Short answer: 2020-12 for new work, draft-07 when an old component forces it.

Timeline

Draft Year Notable
draft-04 2013 id instead of $id; still common in older APIs
draft-06 2017 const, propertyNames
draft-07 2018 if/then/else, readOnly, contentMediaType; best compatibility
2019-09 2019 $defs replaces definitions, unevaluatedProperties
2020-12 2020 prefixItems, $dynamicRef; current recommendation

What 2020-12 improves

Array tuples stop being a special case. draft-07 expresses "first element is A, second is B" with items: [{...}, {...}] plus additionalItems. 2020-12 uses prefixItems for position-specific schemas and items for the rest.

$defs is the standard name. Tooling written after 2019 looks there by default.

unevaluatedProperties works with composition. With allOf, additionalProperties: false rejects fields defined by sibling branches. unevaluatedProperties: false only considers properties actually evaluated by the whole schema, which is what composition needs.

When draft-07 is the right answer

Situation Reason
OpenAPI 3.0 Its schema object is a draft-04/07 subset
Older validators (ajv 6, some Java libraries) They do not know prefixItems or $dynamicRef
Platform mandates a version Some low-code platforms and gateways pin it
Code generators that stop at 07 Unknown keywords are ignored silently

Test the last case directly: feed a prefixItems schema to your validator. If it passes without complaint rather than reporting an unknown keyword, it is ignoring the constraint — the most dangerous outcome of all.

Mixing versions

Always declare $schema. Defaults differ: ajv assumes draft-07, several Python libraries assume 2020-12. The same file then validates differently in two places.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/schemas/order.json",
  "type": "object"
}

Do not $ref across drafts. Behaviour is undefined.

Upgrade in batches. Two drafts in one repository turns "which rules apply here" into tribal knowledge.

FAQ

How do I check whether my validator supports 2020-12?

Feed a schema that uses prefixItems to the validator. An unknown-keyword error means it does not support the draft; passing silently means it is ignoring the constraint, which is worse.

Why should one project use a single draft?

Two drafts in one repository turn "which rules apply here" into tribal knowledge. Upgrade in batches so every file shares the same interpretation.

Should I always declare $schema?

Yes. Defaults differ: ajv assumes draft-07 while several Python libraries assume 2020-12, so the same file can validate differently in two places.

Further reading