What is JSON Schema? — JSON Data Validation Explained
Definition
JSON Schema is an IETF standard (RFC 8927) that provides a vocabulary for annotating and validating JSON documents. It allows you to describe the structure, content types, and constraints of JSON data using a declarative JSON-based format. With JSON Schema, you can ensure that incoming JSON data conforms to expected shapes, types, and value ranges — making it an essential tool for API contracts, form validation, configuration file checking, and automated testing.
JSON Schema is language-agnostic and supported by validators in virtually every programming language, including JavaScript, Python, Java, Go, Rust, Ruby, and more.
Schema Structure
A JSON Schema is itself a JSON document. The top-level structure uses well-known reserved keywords to declare metadata and validation rules:
| Keyword | Purpose |
|---|---|
$schema |
Declares which JSON Schema dialect the schema follows |
$id |
Sets a unique URI identifier for the schema (used for referencing) |
type |
Specifies the expected JSON data type (object, array, string, number, boolean, null) |
properties |
Defines the expected keys and their sub-schemas for an object |
required |
Lists which properties must be present |
additionalProperties |
Controls whether extra properties are allowed |
items |
Defines the schema for array elements |
definitions |
(Draft 4-7) Holds reusable sub-schemas |
$defs |
(Draft 2019-09+) Replacement for definitions |
$ref |
References a sub-schema by its URI or internal path |
allOf, anyOf, oneOf, not |
Boolean logic composition keywords |
Example Schema with Valid and Invalid Data
Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/user-schema.json",
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"email": {
"type": "string",
"format": "email"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"role": {
"type": "string",
"enum": ["admin", "editor", "viewer"]
},
"tags": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true
},
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zipCode": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" }
},
"required": ["street", "city"]
}
},
"required": ["id", "name", "email", "role"]
}✅ Valid JSON
{
"id": 42,
"name": "Alice Johnson",
"email": "alice@example.com",
"age": 34,
"role": "admin",
"tags": ["api", "backend"],
"address": {
"street": "123 Main St",
"city": "San Francisco",
"zipCode": "94105"
}
}❌ Invalid JSON (several violations)
{
"id": -1,
"name": "",
"email": "not-an-email",
"role": "superadmin"
}Why it fails:
idis less thanminimum: 1nameviolatesminLength: 1(empty string)emaildoes not matchformat: "email"roleis not one of theenumvalues ("superadmin"not allowed)
Keyword Overview
Type Constraints
| Keyword | Example | Description |
|---|---|---|
type |
"string" |
Must be string, number, integer, boolean, null, object, or array |
const |
"production" |
Value must equal the given constant |
String Constraints
| Keyword | Example | Description |
|---|---|---|
minLength / maxLength |
5 / 50 |
Character length limits |
pattern |
"^[a-z]+$" |
Regex pattern the string must match |
format |
"email" |
Semantic format: email, uri, date, date-time, uuid, ipv4, ipv6, hostname |
Numeric Constraints
| Keyword | Example | Description |
|---|---|---|
minimum / maximum |
0 / 100 |
Inclusive range |
exclusiveMinimum / exclusiveMaximum |
0 / 100 |
Exclusive range |
multipleOf |
5 |
Value must be a multiple of the given number |
Array Constraints
| Keyword | Example | Description |
|---|---|---|
items |
{ "type": "number" } |
Schema for all elements |
prefixItems |
[{ "type": "string" }, { "type": "number" }] |
Tuple-style item validation (Draft 2020-12+) |
minItems / maxItems |
1 / 10 |
Array length bounds |
uniqueItems |
true |
Ensures no duplicates |
contains |
{ "type": "number" } |
Array must contain at least one matching element |
Object Constraints
| Keyword | Example | Description |
|---|---|---|
properties |
{ "name": { "type": "string" } } |
Per-key schemas |
required |
["name", "email"] |
Mandatory keys |
additionalProperties |
false |
Disallow extra keys |
patternProperties |
{ "^\\w+$": { "type": "string" } } |
Regex-keyed schemas |
minProperties / maxProperties |
1 / 20 |
Object size bounds |
dependentRequired |
{ "credit_card": ["billing_address"] } |
Conditional requirement |
Enum and Default
| Keyword | Example | Description |
|---|---|---|
enum |
["red", "green", "blue"] |
Value must be one of the listed options |
default |
"guest" |
Suggested default value (informational only) |
Boolean Logic Composition
| Keyword | Description |
|---|---|
allOf |
Data must validate against all sub-schemas |
anyOf |
Data must validate against at least one sub-schema |
oneOf |
Data must validate against exactly one sub-schema |
not |
Data must not validate against the sub-schema |
if / then / else |
Conditional validation (Draft 7+) |
Schema Composition
Using $defs and $ref (Draft 2020-12)
Reusable sub-schemas eliminate duplication:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/address-book.json",
"type": "object",
"properties": {
"contacts": {
"type": "array",
"items": { "$ref": "#/$defs/contact" }
}
},
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["street", "city", "country"]
},
"contact": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" },
"address": { "$ref": "#/$defs/address" }
},
"required": ["name", "email"]
}
}
}Composition with allOf, anyOf, oneOf
{
"type": "object",
"properties": {
"paymentMethod": {
"oneOf": [
{ "type": "object", "properties": {
"type": { "const": "credit" },
"cardNumber": { "type": "string", "pattern": "^\\d{16}$" }
},
"required": ["type", "cardNumber"]
},
{ "type": "object", "properties": {
"type": { "const": "paypal" },
"email": { "type": "string", "format": "email" }
},
"required": ["type", "email"]
}
]
}
}
}JSON Schema vs Alternatives
| Feature | JSON Schema | TypeScript | Zod | YAML Schema |
|---|---|---|---|---|
| Scope | Runtime validation | Static types only | Runtime + TypeScript | YAML validation |
| Language | JSON (language-agnostic) | TypeScript | TypeScript | YAML |
| Schema format | JSON | Type annotations | Chainable API | YAML |
| Runtime | ✅ Yes | ❌ No (compile-time) | ✅ Yes | ✅ Yes |
| $ref / reuse | ✅ Built-in | ✅ Interfaces/extend | ✅ .merge() / .extend() |
✅ Anchors/aliases |
| Conditional logic | ✅ if/then/else |
✅ Conditional types | ✅ .refine() / .superRefine() |
❌ Limited |
| Pattern matching | ✅ pattern |
✅ Template literal types | ✅ .regex() |
❌ |
| Code generation | ✅ TypeScript, Zod, Pydantic | N/A | ✅ Type inference | ❌ |
| IETF Standard | ✅ RFC 8927 | ❌ | ❌ | ❌ |
| OpenAPI integration | ✅ Native | ❌ | ❌ | ❌ |
Key takeaway: JSON Schema is the only cross-language, runtime validation standard. TypeScript provides compile-time type safety but cannot validate data at runtime. Zod combines runtime validation with TypeScript inference but is tied to the TS ecosystem. JSON Schema serves as an interchange format that can generate types for any of these tools.
Common Use Cases
API Validation
JSON Schema is the backbone of request/response validation in REST APIs. Frameworks like Express.js (express-json-validator), FastAPI (Pydantic generates JSON Schema), and .NET (JsonSchema<T>) all leverage JSON Schema to enforce API contracts automatically.
Form Generation
Libraries like react-jsonschema-form (RJSF) and @rjsf/core render fully functional HTML forms directly from a JSON Schema. This enables dynamic, data-driven UI without writing form markup by hand.
Documentation and Discovery
JSON Schema provides a clear, self-documenting contract for your data. Combined with tools like JSON Schema Viewer or doc generators, teams can publish interactive documentation that consumers can explore and test.
Automated Testing
Generate test fixtures and boundary-value test cases from your schema. Validate test outputs against the schema to catch regressions automatically.
Configuration File Validation
Validate JSON config files (e.g., manifest.json, chrome-extension manifests, CI/CD configs) against a schema before they reach production.
JSON Schema in OpenAPI
OpenAPI 3.0 and 3.1 both use JSON Schema as the foundation for describing API request and response bodies. OpenAPI 3.1 fully adopts Draft 2020-12, making its schema layer identical to standard JSON Schema.
openapi: 3.1.0
info:
title: User API
version: 1.0.0
paths:
/users:
post:
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
minLength: 1
email:
type: string
format: email
required:
- name
- email
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
format: email
``"
Because OpenAPI uses JSON Schema natively, any tool that understands JSON Schema — validators, generators, documentation builders — works directly with OpenAPI specs.
---
## LangStop JSON Schema Tools
- [JSON Validator](https://langstop.com/json-validator) — Validate JSON syntax and structure
- [JSON Formatter](https://langstop.com/json-formatter) — Pretty-print and beautify JSON
- [JSON Schema GUI Builder](https://langstop.com/json-schema-gui-builder) — Visually build JSON Schema without writing code
- [JSON Schema to TypeScript](https://langstop.com/json-schema-to-typescript) — Convert JSON Schema to TypeScript interfaces
- [JSON Schema to Zod](https://langstop.com/json-schema-to-zod) — Convert JSON Schema to Zod validation schemas
- [JSON to Pydantic](https://langstop.com/json-to-pydantic) — Convert JSON to Pydantic models
- [OpenAPI Editor](https://langstop.com/openapi-editor) — Edit and validate OpenAPI specs that use JSON Schema