What is JSON Schema?
JSON Schema explained: core keywords, composition, Draft-07 vs 2020-12, and practical validation use cases.
JSON Schema is a vocabulary that lets you describe the structure and constraints of a JSON document. Think of it as a type definition for JSON — you write a schema, and any conforming JSON must match it.
It answers questions like: is age a number between 0 and 150? Is email present and a valid email string? If type is "premium", is billingPlan required? JSON Schema lets you express all of this declaratively.
A minimal example
Given this JSON:
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}A JSON Schema that validates it:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "name", "email"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"name": { "type": "string", "minLength": 1 },
"email": { "type": "string", "format": "email" },
"role": { "type": "string", "enum": ["admin", "editor", "viewer"] }
},
"additionalProperties": false
}Core keywords
| Keyword | What it does | Example |
|---|---|---|
type | Constrains the JSON type | "type": "string" |
properties | Defines sub-schemas for object keys | "properties": { "age": { "type": "integer" } } |
required | Array of keys that must be present | "required": ["id", "email"] |
additionalProperties | Whether extra keys are allowed (false = strict) | "additionalProperties": false |
enum | Value must be one of a fixed list | "enum": ["red", "green", "blue"] |
format | Semantic format hint (email, date, uri…) | "format": "date-time" |
minimum / maximum | Numeric range constraints | "minimum": 0, "maximum": 100 |
minLength / maxLength | String length constraints | "minLength": 8 |
pattern | String must match a regex | "pattern": "^[a-z]+" |
items | Schema for array elements | "items": { "type": "number" } |
$ref | References another schema by URI or anchor | "$ref": "#/$defs/Address" |
$defs | Reusable sub-schema definitions (2020-12) | "$defs": { "Address": { … } } |
Composition keywords
Schemas can be combined with boolean logic:
| Keyword | Meaning |
|---|---|
anyOf | Valid if the data matches at least one of the listed schemas |
oneOf | Valid if the data matches exactly one of the listed schemas |
allOf | Valid if the data matches all listed schemas — used for schema inheritance / mixins |
not | Valid if the data does not match the given schema |
if / then / else | Conditional validation — if the if schema matches, apply then; otherwise apply else |
// A field that is either a string or null
{ "anyOf": [{ "type": "string" }, { "type": "null" }] }
// Conditional: if premium, require billingPlan
{
"if": { "properties": { "type": { "const": "premium" } } },
"then": { "required": ["billingPlan"] }
}Draft-07 vs 2020-12
JSON Schema has several published drafts. The two most widely used are:
| Draft-07 | 2020-12 | |
|---|---|---|
| $schema URI | http://json-schema.org/draft-07/schema | https://json-schema.org/draft/2020-12/schema |
| Reusable definitions | definitions | $defs (renamed) |
| Anchors | Limited | $anchor and $dynamicAnchor |
items keyword | Schema for all items, or tuple | Schema for all items; prefixItems for tuples |
| Vocab support | No | Yes — allows modular schema extensions |
| Ecosystem support | Very wide — most validators support it | Growing — preferred for new projects |
Use 2020-12 for new projects if your validator supports it. Use Draft-07 if you need maximum ecosystem compatibility or are targeting tools like OpenAPI 3.0.
Where JSON Schema is used
- API validation — validate request bodies and responses in Express, FastAPI, Spring, etc.
- OpenAPI / Swagger — API definitions use JSON Schema to describe request/response shapes.
- VS Code settings —
settings.jsonandtsconfig.jsonare validated by JSON Schema. - Form generation — tools like react-jsonschema-form generate forms from schemas.
- Configuration files — many tools use JSON Schema to validate their config files.
JSON Schema validates at runtime, while JSON itself is just the data format. For compile-time type checking in TypeScript, you would use TypeScript interfaces or Zod schemas — though tools like zod-to-json-schema can bridge the two.
Try it now