AllJSONTools

Free JSON Developer Tools

JSON Schema Explained: A Practical Guide for Developers

2026-02-20 · 10 min read · By AllJSONTools

JSON Schema
Validation
API
Having JSON issues?

Paste broken JSON and fix it instantly with AI — plain-English explanations included.

Fix JSON with AI

What is JSON Schema?

JSON Schema is a declarative language that lets you describe the structure, constraints, and validation rules of JSON data. Think of it as a blueprint for your JSON: just as an architect’s blueprint defines exactly how a building should look before construction begins, a JSON Schema defines exactly how a piece of JSON should look before your application ever touches it.

Standard JSON parsers can tell you whether a document is syntactically valid — for example, whether every opening brace has a matching closing brace. JSON Schema goes much further: it validates the structure and semantics of your data. It can enforce that a particular field exists, that it holds a string of a certain length, that a number falls within an acceptable range, or that an array contains only unique items. This kind of validation is essential for building reliable APIs, configuration files, and data pipelines.

JSON Schema itself is written in JSON, which means the tools you already use to read, write, and manipulate JSON can work with schemas too. It is an open standard maintained by the JSON Schema community, with widespread support across programming languages and frameworks.

Why Use JSON Schema?

API Request and Response Validation

One of the most common uses for JSON Schema is validating API payloads. When your server receives a POST request, you can validate the body against a schema before your business logic runs. This prevents malformed data from reaching your database and gives callers clear, machine-readable error messages. On the response side, schemas serve as a contract: if your endpoint promises to return an object with an id field and a name field, the schema enforces that promise.

Form Generation

Libraries such as react-jsonschema-form and Formly can read a JSON Schema and automatically generate a fully functional form complete with labels, input types, and validation rules. This approach keeps your form logic in sync with your data model and dramatically reduces the amount of code you need to write and maintain.

Documentation and Data Contracts

A JSON Schema doubles as living documentation. Because it is both human-readable and machine-readable, it can be consumed by documentation generators (such as OpenAPI / Swagger) and by developers browsing the source code. Teams that adopt schema-driven development often find that misunderstandings between frontend and backend developers decrease significantly because the schema serves as a single source of truth.

Testing and Mocking

Schemas enable powerful testing workflows. Tools like json-schema-faker can generate realistic mock data from a schema, letting you populate test databases or simulate API responses without manually crafting fixtures. You can also use schemas in integration tests to assert that a response conforms to the expected shape, catching regressions early.

Basic Structure

Every JSON Schema starts with a few foundational keywords. The $schema keyword declares which draft of the specification your schema conforms to. The type keyword specifies the expected JSON type at the root level. The properties keyword describes the fields an object may contain, and required lists which of those fields must be present.

Below is a minimal schema that describes a simple user object:

json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "description": "A basic user object",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "description": "Unique identifier for the user"
    },
    "name": {
      "type": "string",
      "description": "Full name of the user"
    },
    "email": {
      "type": "string",
      "format": "email",
      "description": "Primary email address"
    }
  },
  "required": ["id", "name", "email"]
}

A JSON document is valid against this schema when it is an object that contains all three required fields with the correct types:

json
{
  "id": 1,
  "name": "Alice Johnson",
  "email": "alice@example.com"
}

And here is an invalid document — the id is a string instead of an integer, and the required email field is missing entirely:

json
{
  "id": "not-a-number",
  "name": "Bob Smith"
}

Common Types and Keywords

JSON Schema supports six primitive types: string, number, integer, boolean, null, and array. There is also the object type. Each type has its own set of validation keywords.

String

Strings can be constrained with minLength, maxLength, pattern (a regular expression), and format (semantic hints like email, uri, date-time, and uuid).

json
{
  "type": "string",
  "minLength": 2,
  "maxLength": 100,
  "pattern": "^[A-Za-z]+$",
  "format": "email"
}

Note that format is treated as an annotation by default in Draft 2020-12. Validators may or may not enforce it unless you explicitly enable format assertion.

Number and Integer

Numeric types accept minimum, maximum, exclusiveMinimum, exclusiveMaximum, and multipleOf. Use integer when you need whole numbers and number when decimals are acceptable.

json
{
  "type": "integer",
  "minimum": 0,
  "maximum": 150,
  "exclusiveMaximum": 151
}

Boolean and Null

The boolean type accepts only true or false. The null type accepts only a JSON null value. These two types have no additional keywords. To allow a field to be either a string or null, you can use a type array: "type": ["string", "null"].

Object

Objects are the most commonly constrained type. Key keywords include properties (defines known fields), required (lists mandatory fields), additionalProperties (controls whether unlisted fields are allowed), and patternProperties (validates field names against a regex). Setting additionalProperties to false is a common practice for strict API validation.

Array

Arrays support items (a schema that every element must match), minItems, maxItems, and uniqueItems. Below is a schema for an array of tags:

json
{
  "type": "array",
  "items": {
    "type": "string",
    "minLength": 1,
    "maxLength": 30
  },
  "minItems": 1,
  "maxItems": 10,
  "uniqueItems": true
}

This schema guarantees the array has between 1 and 10 elements, every element is a non-empty string no longer than 30 characters, and no two elements are identical. You can validate arrays like this instantly using our JSON Schema Validator.

Combining Schemas

JSON Schema provides four composition keywords that let you combine multiple sub-schemas into more sophisticated validation rules:

  • allOf – The data must be valid against all of the listed sub-schemas. This is useful for combining multiple sets of constraints or simulating inheritance.
  • anyOf – The data must be valid against at least one of the listed sub-schemas.
  • oneOf – The data must be valid against exactly one of the listed sub-schemas. This is ideal for union types or discriminated unions.
  • not – The data must not be valid against the given sub-schema.

Here is an example using oneOf to model a payment method that is either a credit card or a bank transfer:

json
{
  "type": "object",
  "oneOf": [
    {
      "properties": {
        "method": { "const": "credit_card" },
        "cardNumber": { "type": "string", "pattern": "^[0-9]{16}$" },
        "expiryDate": { "type": "string", "pattern": "^(0[1-9]|1[0-2])/[0-9]{2}$" },
        "cvv": { "type": "string", "pattern": "^[0-9]{3,4}$" }
      },
      "required": ["method", "cardNumber", "expiryDate", "cvv"]
    },
    {
      "properties": {
        "method": { "const": "bank_transfer" },
        "accountNumber": { "type": "string", "minLength": 8 },
        "routingNumber": { "type": "string", "minLength": 9, "maxLength": 9 }
      },
      "required": ["method", "accountNumber", "routingNumber"]
    }
  ]
}

With this schema, the validator accepts either shape but never a mix of the two. The const keyword on the method field acts as a discriminator, making it easy for the validator to determine which branch applies.

Draft-07 vs Draft 2020-12

JSON Schema has gone through several draft revisions. The two most widely used today are Draft-07 (released in 2018) and Draft 2020-12 (the latest stable release). Understanding the differences helps you choose the right version for your project.

FeatureDraft-07Draft 2020-12
Schema identifier$id$id
exclusiveMinimumBoolean value alongside minimumStandalone numeric value
if / then / elseSupportedSupported
Tuple validationitems (array form) + additionalItemsprefixItems + items
Dynamic referencesNot supported$dynamicRef / $dynamicAnchor
Format assertionEnabled by defaultAnnotation only (opt-in for assertion)
Vocabulary supportNot supported$vocabulary
Library supportNear-universalGrowing (most major libraries support it)

Which should you choose? For new projects, Draft 2020-12 is recommended. It offers cleaner semantics (especially for tuple validation with prefixItems), dynamic references for advanced extension patterns, and a vocabulary system that lets you define custom validation keywords. However, if your toolchain or existing schemas are heavily invested in Draft-07, migration is not urgent — Draft-07 remains fully functional and widely supported.

Real-World Example: User Registration API

Below is a comprehensive JSON Schema for a user registration endpoint. It demonstrates nested objects, conditional validation, string patterns, enumerations, and sensible defaults — everything you would expect in a production-ready schema.

json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://api.example.com/schemas/user-registration",
  "title": "User Registration",
  "description": "Schema for the POST /api/v1/register endpoint",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 30,
      "pattern": "^[a-zA-Z0-9_-]+$",
      "description": "Alphanumeric username with underscores and hyphens"
    },
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 254,
      "description": "Valid email address"
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "Must be at least 8 characters"
    },
    "fullName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "User's full display name"
    },
    "dateOfBirth": {
      "type": "string",
      "format": "date",
      "description": "ISO 8601 date (YYYY-MM-DD)"
    },
    "role": {
      "type": "string",
      "enum": ["user", "admin", "moderator"],
      "default": "user",
      "description": "Account role"
    },
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string", "maxLength": 200 },
        "city": { "type": "string", "maxLength": 100 },
        "state": { "type": "string", "maxLength": 100 },
        "postalCode": { "type": "string", "pattern": "^[0-9A-Za-z -]{3,10}$" },
        "country": {
          "type": "string",
          "minLength": 2,
          "maxLength": 2,
          "description": "ISO 3166-1 alpha-2 country code"
        }
      },
      "required": ["street", "city", "postalCode", "country"],
      "additionalProperties": false
    },
    "preferences": {
      "type": "object",
      "properties": {
        "newsletter": { "type": "boolean", "default": false },
        "theme": {
          "type": "string",
          "enum": ["light", "dark", "system"],
          "default": "system"
        },
        "language": {
          "type": "string",
          "pattern": "^[a-z]{2}(-[A-Z]{2})?$",
          "default": "en",
          "description": "BCP 47 language tag"
        }
      },
      "additionalProperties": false
    },
    "tags": {
      "type": "array",
      "items": { "type": "string", "minLength": 1, "maxLength": 30 },
      "maxItems": 10,
      "uniqueItems": true,
      "default": []
    },
    "agreedToTerms": {
      "type": "boolean",
      "const": true,
      "description": "Must be true to register"
    }
  },
  "required": [
    "username",
    "email",
    "password",
    "fullName",
    "agreedToTerms"
  ],
  "additionalProperties": false
}

This schema enforces usernames that contain only safe characters, limits password length to a sane range, validates the email format, restricts the country code to exactly two characters, and requires that the user has explicitly agreed to the terms of service via the agreedToTerms field (which must be true). The additionalProperties: false setting at both the root level and inside nested objects ensures that unexpected fields are rejected rather than silently ignored.

You can generate schemas like this automatically from your existing JSON data using our JSON Schema Generator tool, which analyzes a sample payload and infers the appropriate types, constraints, and structure.

Getting Started

The best way to learn JSON Schema is to start writing and validating schemas right away. AllJSONTools provides two free tools that make this easy:

  • JSON Schema Generator – Paste any JSON document and instantly generate a valid JSON Schema from it. This is perfect when you already have sample data and want to create a schema without writing it by hand.
  • JSON Schema Validator – Paste a schema in one panel and your JSON data in the other. The validator highlights errors in real time, showing you exactly which fields fail and why.

If you are working with TypeScript, consider libraries like ajv (the fastest JSON Schema validator for JavaScript and Node.js) or zod-to-json-schema if you prefer defining schemas in TypeScript first and converting them to JSON Schema for interoperability. In Python, jsonschema is the de facto standard library, and in Go, gojsonschema is a popular choice.

typescript
import Ajv from "ajv";
import addFormats from "ajv-formats";

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

const schema = {
  type: "object",
  properties: {
    username: { type: "string", minLength: 3 },
    email: { type: "string", format: "email" },
  },
  required: ["username", "email"],
  additionalProperties: false,
};

const validate = ajv.compile(schema);

const data = { username: "alice", email: "alice@example.com" };

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

JSON Schema is a fundamental building block for modern API development, configuration management, and data validation. By defining clear contracts for your data, you reduce bugs, improve documentation, and make your systems more robust. Start with a simple schema, validate it using the tools above, and gradually adopt more advanced features like composition keywords and conditional validation as your needs grow.

Having JSON issues?

Paste broken JSON and fix it instantly with AI — plain-English explanations included.

Fix JSON with AI