What Is JSON Schema and Why You Need It
JSON Schema is a declarative language for defining the structure, content, and constraints of JSON data. Think of it as a contract: the schema describes what valid data looks like, and a validator checks whether actual data conforms to that contract.
Without JSON Schema, validating JSON means writing manual checks scattered across your codebase. You write if (!data.name) here, if (typeof data.age !== 'number') there, and hope you remembered every field and edge case. When the data structure changes, you hunt through your code to update every check. This approach does not scale.
JSON Schema solves this by centralizing your validation rules into a single, readable document. Here is a minimal example:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name"]
}
This schema says: the data must be an object, it may have a name (string) and an age (non-negative integer), and name is required. Any JSON document can be validated against this schema in milliseconds using libraries available in every major language.
Where JSON Schema is used:
- API validation -- validate request and response bodies against a schema before processing
- Configuration files -- ensure config files contain the right keys and value types before the application starts
- Form generation -- generate UI forms automatically from a schema definition
- Documentation -- schemas serve as machine-readable documentation for your data models
- Code generation -- generate TypeScript interfaces, database models, or mock data from schemas
- Testing -- validate API responses in integration tests against the expected schema
You can test any schema interactively using the NexTool JSON Schema Validator, which runs entirely in your browser with instant feedback on every change.
JSON Schema Draft 7: The Standard You Should Use
JSON Schema has evolved through several drafts. The most widely supported is Draft 7 (officially draft-07), published in 2018. Newer drafts exist (2019-09 and 2020-12), but Draft 7 has the broadest library support and the largest body of documentation, tutorials, and tooling.
Why Draft 7
Every major validation library supports Draft 7 out of the box: ajv (JavaScript), jsonschema (Python), gojsonschema (Go), everit-org/json-schema (Java), and NJsonSchema (.NET). If you pick Draft 7, you will never encounter a "this draft is not supported" error regardless of your tech stack.
Anatomy of a Draft 7 Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/schemas/user.json",
"title": "User",
"description": "A registered user in the system",
"type": "object",
"properties": {
...
},
"required": [...]
}
$schema-- declares which JSON Schema draft is used. Always include this.$id-- a unique identifier (URI) for this schema. Useful for referencing schemas from other schemas.titleanddescription-- human-readable metadata. Does not affect validation, but helps documentation tooling.type-- the expected JSON type at the root level.properties-- defines the fields and their individual schemas.required-- an array of property names that must be present.
Start with Draft 7. It covers every common validation scenario, has universal library support, and an enormous ecosystem of tutorials and tools. Move to a newer draft only when you need a specific feature it provides, such as prefixItems for tuple validation in Draft 2020-12.
Basic Types and Constraints
JSON Schema supports seven types that map directly to JSON's data types. Each type has its own set of validation keywords.
string
Validates that the value is a string. Additional constraints include minimum and maximum length, regex patterns, and format hints.
{
"type": "string",
"minLength": 1,
"maxLength": 255
}
number and integer
Both validate numeric values. integer rejects values with decimal points. Use minimum, maximum, exclusiveMinimum, and exclusiveMaximum to constrain the range. multipleOf enforces divisibility.
{
"type": "integer",
"minimum": 1,
"maximum": 120,
"multipleOf": 1
}
boolean
Accepts only true or false. No additional constraints.
{ "type": "boolean" }
null
Accepts only null. Useful in combination with other types to allow nullable fields.
{ "type": ["string", "null"] }
Passing an array to type means the value can be any of the listed types. The example above accepts either a string or null.
object
Validates objects (key-value pairs). Use properties for field definitions, required for mandatory fields, additionalProperties to control whether unlisted keys are allowed, and minProperties/maxProperties for size constraints.
array
Validates arrays. Use items for the schema of each element, minItems/maxItems for length, and uniqueItems to forbid duplicates.
enum
While not a type itself, enum restricts a value to a fixed set of options. It works with any type.
{
"type": "string",
"enum": ["active", "inactive", "suspended"]
}
Required Fields and Default Values
A common misunderstanding is that defining a property in properties makes it required. It does not. In JSON Schema, all properties are optional by default. You must explicitly declare which ones are mandatory.
{
"type": "object",
"properties": {
"username": { "type": "string", "minLength": 3 },
"email": { "type": "string", "format": "email" },
"bio": { "type": "string", "maxLength": 500 }
},
"required": ["username", "email"]
}
In this schema, username and email are required. The bio field can be omitted entirely without causing a validation error. But if bio is provided, it must be a string with at most 500 characters.
Controlling Extra Properties
By default, JSON Schema allows properties not listed in properties. To reject unknown fields, set additionalProperties to false.
{
"type": "object",
"properties": {
"username": { "type": "string" },
"email": { "type": "string" }
},
"required": ["username", "email"],
"additionalProperties": false
}
Now any JSON object with a key other than username or email will fail validation. This is extremely useful for API endpoints where you want strict control over the payload shape.
Default Values
The default keyword declares a default value for a property. Note that most validators do not insert defaults automatically -- they just report it as metadata. If you want default-filling behavior, use a library like ajv with the useDefaults option enabled.
{
"type": "object",
"properties": {
"role": { "type": "string", "default": "viewer" },
"active": { "type": "boolean", "default": true }
}
}
Nested Objects
Real-world data is rarely flat. Users have addresses. Orders have line items. Configurations have nested sections. JSON Schema handles nesting by composing schemas inside each other.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^[0-9]{5}$" },
"country": { "type": "string", "minLength": 2, "maxLength": 2 }
},
"required": ["street", "city", "country"]
}
},
"required": ["name", "address"]
}
This schema requires a name and an address object. The address itself must contain street, city, and a two-letter country code. The zip field is optional but if present must be exactly five digits.
Reusing Schemas with $ref
When the same structure appears in multiple places, use $ref to reference a shared definition instead of duplicating it.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["street", "city", "country"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
}
}
Both billing_address and shipping_address share the same schema. Change the definition once, and both references pick up the change. This keeps large schemas maintainable and free of redundancy. You can test complex nested schemas instantly with the NexTool JSON Schema Validator.
Arrays and Tuples
Arrays in JSON Schema are validated using the items keyword. The simplest form validates that every element matches a single schema.
Homogeneous Arrays
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}
This schema requires an array of 1 to 10 unique strings. An empty array fails. An array with duplicate values fails. An array containing a number fails.
Arrays of Objects
This is the most common real-world pattern: an array where each element is an object with a defined structure.
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
},
"minItems": 1
}
Every element in the array must be an object with at least id (integer) and name (string). The email field is optional per element.
Tuple Validation (Fixed-Position Arrays)
Sometimes an array has a fixed structure where each position means something different, like [latitude, longitude]. In Draft 7, use items as an array of schemas combined with additionalItems.
{
"type": "array",
"items": [
{ "type": "number", "minimum": -90, "maximum": 90 },
{ "type": "number", "minimum": -180, "maximum": 180 }
],
"additionalItems": false
}
This validates a two-element array where the first number is a latitude (-90 to 90) and the second is a longitude (-180 to 180). No additional elements are allowed.
Patterns and Formats
String validation goes far beyond just checking the type. JSON Schema gives you two mechanisms for constraining string content: regex patterns and semantic formats.
Regular Expression Patterns
The pattern keyword validates a string against a regular expression. The regex must match somewhere in the string (it does not require a full match unless you use ^ and $ anchors).
{
"type": "object",
"properties": {
"phone": {
"type": "string",
"pattern": "^\\+[1-9][0-9]{6,14}$"
},
"slug": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
},
"hex_color": {
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$"
}
}
}
Patterns use ECMA-262 regular expression syntax. Remember to double-escape backslashes in JSON strings (\\d instead of \d).
Built-In Formats
The format keyword provides semantic validation for common string types. In Draft 7, format validation is optional by default -- validators may treat it as an annotation rather than an assertion. Libraries like ajv require explicit opt-in via configuration.
{
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"website": { "type": "string", "format": "uri" },
"created_at": { "type": "string", "format": "date-time" },
"birth_date": { "type": "string", "format": "date" },
"server_ip": { "type": "string", "format": "ipv4" },
"request_id": { "type": "string", "format": "uuid" }
}
}
Supported formats in Draft 7 include: date-time, date, time, email, idn-email, hostname, idn-hostname, ipv4, ipv6, uri, uri-reference, iri, iri-reference, uri-template, json-pointer, relative-json-pointer, and regex.
Format validation is not enforced by default in most validators. In ajv, you need to install the ajv-formats plugin and add it explicitly. Without it, "format": "email" is treated as a hint, not a rule. Always check your validator's documentation.
Schema Composition: allOf, anyOf, oneOf, not
JSON Schema provides four keywords for combining schemas. These let you express complex validation logic that goes beyond what individual type checks can do.
allOf -- Must Match All
The data must satisfy every schema in the array. This is commonly used to combine a base schema with additional constraints.
{
"allOf": [
{ "$ref": "#/definitions/base_user" },
{
"properties": {
"role": { "const": "admin" },
"permissions": { "type": "array", "minItems": 1 }
},
"required": ["role", "permissions"]
}
]
}
anyOf -- Must Match At Least One
The data must satisfy at least one of the listed schemas. Useful for accepting multiple valid shapes.
{
"anyOf": [
{ "type": "string", "minLength": 1 },
{ "type": "number", "minimum": 0 }
]
}
oneOf -- Must Match Exactly One
The data must satisfy exactly one schema and fail all others. This is stricter than anyOf and is used for discriminated unions.
{
"oneOf": [
{
"properties": { "type": { "const": "email" }, "address": { "type": "string" } },
"required": ["type", "address"]
},
{
"properties": { "type": { "const": "sms" }, "phone": { "type": "string" } },
"required": ["type", "phone"]
}
]
}
not -- Must Not Match
The data must fail validation against the given schema. Useful for excluding specific values or patterns.
{
"type": "string",
"not": { "enum": ["admin", "root", "superuser"] }
}
Validation in Practice: Working Code
Knowing the schema syntax is half the picture. Here is how to actually validate JSON against a schema in the languages you are most likely to use.
JavaScript with ajv
import Ajv from "ajv";
import addFormats from "ajv-formats";
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const schema = {
type: "object",
properties: {
name: { type: "string", minLength: 1 },
email: { type: "string", format: "email" },
age: { type: "integer", minimum: 0 }
},
required: ["name", "email"],
additionalProperties: false
};
const validate = ajv.compile(schema);
const data = { name: "Alice", email: "alice@example.com", age: 30 };
const valid = validate(data);
if (!valid) {
console.log("Validation errors:", validate.errors);
} else {
console.log("Data is valid");
}
Python with jsonschema
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name", "email"]
}
data = {"name": "Alice", "email": "alice@example.com", "age": 30}
try:
validate(instance=data, schema=schema)
print("Data is valid")
except ValidationError as e:
print(f"Validation error: {e.message}")
For quick validation without writing code, paste your schema and data into the NexTool JSON Schema Validator. For formatting your JSON before validation, use the JSON Formatter. And for editing complex JSON structures visually, the JSON Editor lets you build valid JSON with a tree interface.
Validate Your JSON Schema Now
Paste your schema and data side by side. Get instant validation results with detailed error messages. No signup, no server uploads.
Open JSON Schema ValidatorCommon JSON Schema Mistakes
After helping thousands of developers debug their schemas, these are the errors we see most often.
1. Forgetting the required Array
Defining a property in properties does not make it required. Without an explicit required array, every single property is optional. An empty object {} will pass validation against a schema that has properties but no required array.
2. Using additionalProperties Too Aggressively with allOf
When you use allOf to combine schemas, each sub-schema is evaluated independently. If one sub-schema sets additionalProperties: false but the other defines different properties, validation will fail because each sub-schema does not know about the other's properties. Solution: put additionalProperties at the top level, not inside allOf branches.
3. Confusing pattern with Full-String Match
The pattern keyword checks for a match anywhere in the string, not a full match. If you want the entire string to match, you must use ^ at the start and $ at the end of your regex. Without anchors, "pattern": "[0-9]+" will match "abc123xyz" because it contains digits somewhere.
4. Expecting format to Validate by Default
As noted earlier, most validators treat format as an annotation, not an assertion. If your "format": "email" is not rejecting invalid emails, you need to enable format validation explicitly in your library's configuration.
5. Not Using $ref for Reusable Definitions
Duplicating the same schema in multiple places makes maintenance painful and error-prone. Use definitions (Draft 7) or $defs (Draft 2019-09+) and reference them with $ref. Your schemas will be shorter, clearer, and easier to update.
Frequently Asked Questions
What is JSON Schema validation?
JSON Schema validation is the process of checking whether a JSON document conforms to a predefined structure described by a JSON Schema. The schema defines what types, properties, and constraints are allowed. A validator compares your data against the schema and reports whether it passes or fails, with specific error messages for each violation. It goes beyond syntax checking by enforcing data types, required fields, value ranges, string patterns, and structural rules.
Which JSON Schema draft should I use?
For most projects, use Draft 7 (draft-07). It is the most widely supported draft across all major programming languages and validation libraries. Newer drafts like 2019-09 and 2020-12 add features such as $defs and prefixItems, but library support is less universal. If maximum compatibility is your priority, Draft 7 is the safest choice.
How do I validate JSON against a schema online?
Paste your JSON data and your JSON Schema into a browser-based tool like NexTool JSON Schema Validator. It runs entirely in your browser, so your data never leaves your machine. You get instant validation results with detailed error messages pinpointing exactly which fields fail and why.
What is the difference between required and optional in JSON Schema?
All properties defined inside the properties keyword are optional by default. To make a property mandatory, list its name in the required array at the same level as properties. A JSON object missing a required field will fail validation. A missing optional field is silently ignored.
Can JSON Schema validate nested objects and arrays?
Yes. JSON Schema handles nested structures through recursive schema definitions. For nested objects, define the inner object inside the parent's properties with its own type, properties, and required fields. For arrays, use "type": "array" with an items keyword containing the element schema. You can validate arrays of objects, enforce minimum and maximum lengths, and require unique items with "uniqueItems": true.
Explore 150+ Free Developer Tools
JSON Schema Validator is one of 150+ free tools on NexTool. Format JSON, test regex, convert data, compress images, and more -- all in your browser.
Browse All Free Tools