JSON Schema is a language for describing the structure and constraints of JSON data. A schema defines field types, required fields, value ranges, string formats, and nested objects. Schemas can be used to validate incoming data, generate documentation and TypeScript types, and describe API contracts. This article covers JSON Schema versions (draft-07, 2020-12), key terms, practical examples, libraries, and integration with OpenAPI.
To validate JSON against a schema, use the JSON Schema Validator on reChecker.
What is JSON Schema?
JSON Schema is itself a JSON document that describes the permitted structure of other JSON documents. A schema answers questions such as: which fields are required, what types the values have, and what constraints apply (minimums, maximums, patterns, formats).
Versions: draft-07 and 2020-12
- draft-07 (JSON Schema Draft 7) — a stable, widely supported version. It is used in OpenAPI 3.0 and many libraries.
- 2020-12 (JSON Schema 2020-12) — the current version, with improvements including
$dynamicRef,$anchor, conditional schemas, and improved support fornull.
The version is specified in $schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema"
}Or, for draft-07:
{
"$schema": "http://json-schema.org/draft-07/schema#"
}Key terms
type
The value type: string, number, integer, boolean, array, object, null.
{
"type": "string"
}To allow multiple types, use an array:
{
"type": ["string", "null"]
}properties and additionalProperties
properties describes an object's fields. additionalProperties specifies whether fields not listed in properties are allowed.
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"additionalProperties": false
}required
An array of required fields:
{
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"password": { "type": "string", "minLength": 8 }
},
"required": ["email", "password"]
}string: minLength, maxLength, pattern, format
{
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[a-zA-Z0-9_]+$",
"format": "email"
}Common format values: email, uri, date, date-time, uuid, ipv4, ipv6.
number/integer: minimum, maximum, exclusiveMinimum, exclusiveMaximum
{
"type": "integer",
"minimum": 0,
"maximum": 120,
"exclusiveMaximum": true
}array: items, minItems, maxItems
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10
}For tuples (different types at different positions), use an array in items:
{
"type": "array",
"items": [
{ "type": "string" },
{ "type": "integer" }
]
}enum
Allowed values:
{
"type": "string",
"enum": ["draft", "published", "archived"]
}$ref and $defs
Reusing schemas:
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"shipping": { "$ref": "#/$defs/address" },
"billing": { "$ref": "#/$defs/address" }
}
}Practical examples
User validation
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"email": { "type": "string", "format": "email" },
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
"age": { "type": "integer", "minimum": 0, "maximum": 150 },
"role": { "type": "string", "enum": ["user", "admin", "moderator"] }
},
"required": ["email", "name"],
"additionalProperties": false
}API contract (request)
{
"type": "object",
"properties": {
"query": { "type": "string" },
"page": { "type": "integer", "minimum": 1, "default": 1 },
"limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
},
"required": ["query"]
}Nested objects
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^[0-9]{5,6}$" }
}
}
}
}
}
}Libraries and tools
Ajv (JavaScript/TypeScript)
A popular validation library:
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) console.log(validate.errors);Python: jsonschema
import jsonschema
jsonschema.validate(instance=data, schema=schema)OpenAPI and JSON Schema
OpenAPI 3.x uses a subset of JSON Schema to describe request and response bodies. Schemas in components.schemas are JSON Schema with a few differences. Tools such as Swagger UI and client generators rely on these schemas. When migrating from OpenAPI 2.0 (Swagger) to 3.x, check keyword compatibility—2.0 used an outdated schema version.
Generating code from schemas
JSON Schema can be used to generate TypeScript types, validation classes, forms, and documentation. Popular tools include quicktype, json-schema-to-typescript, openapi-generator. This reduces manual work and minimizes discrepancies between the schema and the code.
Conditional schemas: if/then/else, oneOf, anyOf, allOf
Conditional constructs are used for complex validation logic:
- oneOf — the data must match exactly one of the schemas
- anyOf — the data must match at least one
- allOf — the data must match all listed schemas
- if/then/else — if the condition
ifis met,thenapplies; otherwise,elseapplies
Example: the type field determines which fields are required:
{
"if": { "properties": { "type": { "const": "company" } }, "required": ["type"] },
"then": { "required": ["companyName"] },
"else": { "required": ["firstName", "lastName"] }
}JSON Schema Validator on reChecker
The JSON Schema Validator on reChecker lets you:
- Enter JSON and a schema in separate fields
- Check whether the data matches the schema
- Get a list of errors with paths to the fields
- Debug schemas before using them in code
The tool supports draft-07 and 2020-12. It is useful for developers writing and debugging schemas, as well as investigating validation errors.
Common schema-writing mistakes
- Forgetting required — a field may be missing without the validator reporting an error
- An overly permissive schema —
additionalProperties: trueallows extra fields by default; for APIs, it is better to explicitly disallow them - An invalid $ref — the path must point to an existing definition in
$defsor an external file - format without validation — not all validators check
formatby default; in Ajv,formatmust be added separately
Recommendations
- Schema version — specify
$schemaexplicitly - additionalProperties — set it to
falsefor a strict contract - format — support depends on the validator; check the documentation
- $ref — use it to reuse schemas and reduce duplication
- Testing — validate edge cases and invalid data
- Documentation — add
titleanddescriptionto fields for automatic documentation generation
FAQ
How does draft-07 differ from 2020-12?
2020-12 adds $dynamicRef, $anchor, improved support for null, and conditional schemas. For most tasks, draft-07 is sufficient. Choose 2020-12 if you need the new features or compatibility with current tools.
Can JSON Schema be used with TypeScript?
Yes. Tools such as json-schema-to-typescript generate TypeScript types from schemas. There are also runtime validation libraries that infer types (for example, Zod, which is not JSON Schema but solves similar problems).
How do I describe an array of objects with different structures?
Use oneOf, anyOf, or allOf in items:
{
"type": "array",
"items": {
"oneOf": [
{ "type": "object", "properties": { "type": { "const": "A" } } },
{ "type": "object", "properties": { "type": { "const": "B" } } }
]
}
}Does OpenAPI support the full JSON Schema specification?
OpenAPI 3.x uses a subset of JSON Schema. For example, it does not support $ref to external files in arbitrary locations, or some keywords. For complex schemas, check the OpenAPI documentation.
Which tool should I use to validate JSON against a schema?
The JSON Schema Validator on reChecker is a free online tool. Enter JSON and a schema to get the validation result and a list of errors with paths. It supports draft-07 and 2020-12. It is suitable for developers writing schemas and debugging APIs.