JSON Schema is the industry standard for describing and validating JSON data structures. Whether you’re enforcing API request payloads, validating configuration files, or building form validation logic, a JSON schema validator online lets you test schemas and sample data instantly — no library installation, no test harness required.

Validate your JSON against a schema now →

What Is JSON Schema?

JSON Schema is a declarative vocabulary for annotating and validating JSON documents. A schema is itself a JSON (or YAML) document that describes the expected shape, types, and constraints of data.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["id", "email", "role"],
  "properties": {
    "id": { "type": "integer", "minimum": 1 },
    "email": { "type": "string", "format": "email" },
    "role": { "type": "string", "enum": ["admin", "editor", "viewer"] },
    "createdAt": { "type": "string", "format": "date-time" }
  },
  "additionalProperties": false
}

This schema ensures any validated JSON object has the three required fields, that id is a positive integer, email is a valid email address, and role is one of the three allowed values.

JSON Schema Draft Versions

The specification has evolved significantly. Understanding the version landscape prevents confusion when schemas behave unexpectedly:

DraftReleasedKey Additions
Draft-042013Core vocabulary, $ref, allOf/anyOf/oneOf
Draft-062017const, contains, propertyNames, readOnly
Draft-072019if/then/else, writeOnly, $comment
2019-092019$defs, unevaluatedProperties, $anchor
2020-122021Prefix items, $dynamicRef, improved $ref

Always declare the draft with $schema. Without it, validators may apply different defaults. Most production use today is on draft-07 or 2020-12.

Core Schema Keywords

Type Constraints

{ "type": "string" }
{ "type": "integer" }
{ "type": "number" }
{ "type": "boolean" }
{ "type": "null" }
{ "type": "array" }
{ "type": "object" }

// Multiple allowed types:
{ "type": ["string", "null"] }

Object Constraints

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 }
  },
  "required": ["name"],
  "additionalProperties": false,
  "minProperties": 1,
  "maxProperties": 10
}

additionalProperties: false is the single most effective safety constraint — it rejects any key not listed in properties, catching typos and unexpected fields.

String Constraints

{
  "type": "string",
  "minLength": 3,
  "maxLength": 100,
  "pattern": "^[a-z][a-z0-9_]*$",
  "format": "email"
}

Common format values: email, uri, date, date-time, time, ipv4, ipv6, uuid. Note that format validation is optional by default — validators must be configured to enforce it.

Array Constraints

{
  "type": "array",
  "items": { "type": "string" },
  "minItems": 1,
  "maxItems": 50,
  "uniqueItems": true
}

In draft 2020-12, items was renamed to prefixItems for tuple validation. Use items for homogeneous arrays, prefixItems for positional tuples.

Numeric Constraints

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMinimum": 0,
  "multipleOf": 0.5
}

Enumeration and Const

// One of several allowed values:
{ "enum": ["draft", "published", "archived"] }

// Exactly one value (useful for discriminated unions):
{ "const": "v2" }

Composition Keywords

// Must match ALL subschemas:
{ "allOf": [{ "type": "string" }, { "minLength": 1 }] }

// Must match AT LEAST ONE subschema:
{ "anyOf": [{ "type": "string" }, { "type": "number" }] }

// Must match EXACTLY ONE subschema:
{ "oneOf": [
  { "type": "string", "format": "email" },
  { "type": "string", "format": "uri" }
] }

// Must NOT match the subschema:
{ "not": { "type": "null" } }

Conditional Validation (Draft-07+)

{
  "if": { "properties": { "type": { "const": "company" } } },
  "then": { "required": ["companyName", "taxId"] },
  "else": { "required": ["firstName", "lastName"] }
}

This is one of JSON Schema’s most powerful features — enforcing different required fields based on the value of another field.

Schema References and Reuse

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {
    "address": {
      "type": "object",
      "required": ["street", "city", "country"],
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "country": { "type": "string", "minLength": 2, "maxLength": 2 }
      }
    }
  },
  "type": "object",
  "properties": {
    "billingAddress": { "$ref": "#/$defs/address" },
    "shippingAddress": { "$ref": "#/$defs/address" }
  }
}

$defs (or definitions in older drafts) keeps schemas DRY. $ref supports both local (#/...) and remote (https://...) references.

Validating JSON Schema in Code

Node.js (AJV)

AJV is the fastest and most widely used JavaScript JSON Schema validator:

npm install ajv ajv-formats
import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);

const schema = {
  type: 'object',
  required: ['email', 'age'],
  properties: {
    email: { type: 'string', format: 'email' },
    age: { type: 'integer', minimum: 18 },
  },
  additionalProperties: false,
};

const validate = ajv.compile(schema);
const data = { email: 'user@example.com', age: 25 };

if (validate(data)) {
  console.log('Valid');
} else {
  console.log('Errors:', validate.errors);
}

AJV compiles schemas to optimized JavaScript functions, making validation extremely fast — suitable for hot request paths.

Python (jsonschema)

pip install jsonschema
import jsonschema
from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "required": ["email", "age"],
    "properties": {
        "email": {"type": "string", "format": "email"},
        "age": {"type": "integer", "minimum": 18},
    },
    "additionalProperties": False,
}

data = {"email": "user@example.com", "age": 25}

try:
    validate(instance=data, schema=schema)
    print("Valid")
except ValidationError as e:
    print(f"Invalid: {e.message}")
    print(f"Path: {list(e.absolute_path)}")

For all errors (not just the first), use jsonschema.Draft202012Validator:

from jsonschema import Draft202012Validator

validator = Draft202012Validator(schema)
errors = list(validator.iter_errors(data))
for error in errors:
    print(f"{'.'.join(str(p) for p in error.path)}: {error.message}")

Go (gojsonschema / santhosh-tekuri)

go get github.com/santhosh-tekuri/jsonschema/v6
package main

import (
    "fmt"
    "strings"

    "github.com/santhosh-tekuri/jsonschema/v6"
)

func main() {
    schemaJSON := `{
        "type": "object",
        "required": ["email", "age"],
        "properties": {
            "email": {"type": "string", "format": "email"},
            "age": {"type": "integer", "minimum": 18}
        }
    }`

    compiler := jsonschema.NewCompiler()
    compiler.AddResource("schema.json", strings.NewReader(schemaJSON))
    schema, err := compiler.Compile("schema.json")
    if err != nil {
        panic(err)
    }

    data := map[string]any{"email": "user@example.com", "age": 25}
    if err := schema.Validate(data); err != nil {
        fmt.Println("Invalid:", err)
    } else {
        fmt.Println("Valid")
    }
}

Java (networknt/json-schema-validator)

<dependency>
  <groupId>com.networknt</groupId>
  <artifactId>json-schema-validator</artifactId>
  <version>1.5.3</version>
</dependency>
import com.networknt.schema.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Set;

ObjectMapper mapper = new ObjectMapper();
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);

String schemaJson = """
    {
      "type": "object",
      "required": ["email"],
      "properties": {
        "email": {"type": "string", "format": "email"}
      }
    }
    """;

JsonSchema schema = factory.getSchema(schemaJson);
JsonNode data = mapper.readTree("{\"email\": \"user@example.com\"}");

Set<ValidationMessage> errors = schema.validate(data);
if (errors.isEmpty()) {
    System.out.println("Valid");
} else {
    errors.forEach(e -> System.out.println(e.getMessage()));
}

Real-World Use Cases

API Request Validation

Validate incoming API payloads at the gateway or middleware layer before they reach business logic:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "CreateOrderRequest",
  "type": "object",
  "required": ["customerId", "items", "shippingAddress"],
  "properties": {
    "customerId": { "type": "string", "format": "uuid" },
    "items": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["productId", "quantity"],
        "properties": {
          "productId": { "type": "string" },
          "quantity": { "type": "integer", "minimum": 1 }
        },
        "additionalProperties": false
      }
    },
    "couponCode": { "type": "string", "pattern": "^[A-Z0-9]{6,12}$" }
  }
}

Configuration File Validation

Validate application configs at startup and fail fast with clear error messages instead of cryptic runtime errors:

{
  "type": "object",
  "required": ["server", "database"],
  "properties": {
    "server": {
      "type": "object",
      "required": ["port"],
      "properties": {
        "port": { "type": "integer", "minimum": 1024, "maximum": 65535 },
        "host": { "type": "string", "default": "0.0.0.0" },
        "tls": { "type": "boolean", "default": false }
      }
    },
    "database": {
      "type": "object",
      "required": ["url"],
      "properties": {
        "url": { "type": "string", "format": "uri" },
        "poolSize": { "type": "integer", "minimum": 1, "maximum": 100, "default": 10 }
      }
    }
  }
}

OpenAPI Integration

OpenAPI 3.x uses a JSON Schema subset to define request/response bodies. Keeping standalone schemas in sync with your OpenAPI spec prevents contract drift.

JSON Schema vs Runtime Validation Libraries

ApproachPortabilityLanguage SupportLearning CurveTooling
JSON SchemaHigh (language-neutral)All major languagesMediumExcellent
TypeScript (Zod/Yup)TypeScript onlyTypeScript/JSLowGood
Pydantic (Python)Python onlyPythonLowGood
Protobuf/gRPCHigh (binary)AllHighExcellent
OpenAPI specHighAllMediumExcellent

JSON Schema wins when you need a single canonical schema shared across a polyglot stack — define once, validate in any language.

Common Mistakes

Not setting additionalProperties: false — your schema accepts any extra field, making it trivial for clients to pass unexpected data.

Relying on format without configuring the validatorformat: "email" is an annotation, not a constraint, unless you explicitly enable format validation in your validator.

Mixing draft versions — using $defs (2019-09+) while declaring draft-07 in $schema causes undefined behavior.

Forgetting required — without required, all properties are optional by default. A schema with properties but no required array validates against {}.

Using type: "integer" for IDs from databases — large integer IDs (64-bit) can exceed JavaScript’s safe integer range. Consider "type": "string" or add "maximum": 9007199254740991.

Online JSON Schema Validator

Testing schemas against sample data locally requires setting up a validator, loading files, and running code. ZeroTool’s JSON Schema validator eliminates all that friction:

  • Paste your JSON Schema and sample JSON side by side
  • Instant validation with error paths highlighted
  • Supports draft-04, draft-06, draft-07, 2019-09, and 2020-12
  • 100% local processing — no data leaves your browser

Try the JSON Schema validator →