Guide2026-03-0710 min read

JSON Schema Guide: Getting Started with Data Validation

What is JSON Schema?

JSON Schema is a declarative standard for defining the structure, data types, and constraints of JSON data. Just as a type system in a programming language validates the types of variables, JSON Schema validates whether JSON data conforms to an expected format. It answers questions like: "Is this field a string?", "Is this number between 1 and 100?", and "Are all required fields present?"

JSON Schema itself is written in JSON, so there is no new syntax to learn. If you already know how to read and write JSON, you can start using JSON Schema right away. It is widely used for API contract definition, form validation, configuration file verification, and automated documentation generation.

Why Use JSON Schema?

JSON is an inherently flexible format — it has no built-in mechanism to enforce types or structure. While this flexibility is a strength, it can also be a liability. Without explicit validation, malformed data can slip through and cause runtime errors that are difficult to debug. JSON Schema addresses this problem by providing a clear, machine-readable contract for your data.

API Contracts

When frontend and backend teams (or multiple microservices) need to exchange data, JSON Schema provides a single source of truth for the expected request and response formats. Both sides can validate data against the schema, catching mismatches early and preventing data integrity bugs from reaching production.

Data Validation

You can automatically validate API request bodies, user input, webhook payloads, and more against a JSON Schema. Libraries like Ajv (JavaScript), jsonschema (Python), and everit-org/json-schema (Java) make it easy to integrate schema-based validation into your application code.

Documentation

A JSON Schema serves as living documentation for your data structures. By including description fields, you can clearly document the purpose of each property. Tools can automatically generate human- readable API documentation from JSON Schema definitions, ensuring your docs are always in sync with your actual data contracts.

Basic Keywords

Let's explore the most fundamental keywords you will use in almost every JSON Schema.

type

The type keyword specifies the expected data type. Valid values are string, number, integer, boolean, null, object, and array.

{
  "type": "string"
}

properties

The properties keyword defines the schema for each property of an object. Each key in the properties object corresponds to a property name, and its value is a sub-schema that describes the expected type and constraints for that property.

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer"
    }
  }
}

required

The required keyword specifies an array of property names that must be present in the JSON object. If any of the listed properties are missing, validation fails.

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "email": { "type": "string" }
  },
  "required": ["name", "email"]
}

description

The description keyword adds a human-readable explanation to a schema or property. While it has no effect on validation, it is invaluable for documentation and for making schemas self-explanatory.

{
  "type": "object",
  "description": "An object representing user information",
  "properties": {
    "name": {
      "type": "string",
      "description": "The user's full name"
    }
  }
}

Type-Specific Validation

JSON Schema provides specialized validation keywords for each data type, allowing you to define fine-grained constraints.

String Validation

You can constrain string length, enforce a regular expression pattern, or validate against a predefined format.

{
  "type": "string",
  "minLength": 1,
  "maxLength": 100,
  "pattern": "^[a-zA-Z0-9]+$"
}

The format keyword validates strings against well-known formats such as email, uri, date-time, ipv4, and uuid.

{
  "type": "string",
  "format": "email"
}

Number / Integer Validation

You can specify minimum and maximum values, exclusive bounds, and multiples.

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

// Integer-only validation
{
  "type": "integer",
  "minimum": 1,
  "maximum": 150
}

Array Validation

You can validate the type of array items, set length constraints, and require all items to be unique.

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

Object Validation

You can define expected properties, mark some as required, and control whether additional (unexpected) properties are allowed.

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": ["name"],
  "additionalProperties": false
}

When additionalProperties is set to false, any properties not explicitly defined in properties will cause validation to fail. This is useful for strict API contracts where unexpected fields should be rejected.

Nested Schemas and $ref

When writing complex schemas, you often need to reuse the same definition in multiple places. The $ref keyword lets you reference a reusable schema definition, keeping your schemas DRY (Don't Repeat Yourself). Common definitions are placed in $defs (or the older definitions keyword) and referenced using a JSON Pointer.

{
  "type": "object",
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zipcode": { "type": "string" }
      },
      "required": ["street", "city"]
    }
  },
  "properties": {
    "homeAddress": { "$ref": "#/$defs/address" },
    "workAddress": { "$ref": "#/$defs/address" }
  }
}

In this example, the address schema is defined once and referenced twice — for both homeAddress and workAddress. This approach makes maintenance much easier: if the address format changes, you only need to update it in one place.

enum and const

These keywords allow you to restrict values to a specific set.

enum

The enum keyword specifies an array of allowed values. The data must match one of the listed values exactly.

{
  "type": "string",
  "enum": ["active", "inactive", "suspended"]
}

Note that enum is not restricted to strings — it can contain numbers, booleans, null, or even objects and arrays.

const

The const keyword restricts the value to exactly one specific value.

{
  "properties": {
    "version": {
      "const": "1.0.0"
    }
  }
}

Conditional Schemas: if/then/else

JSON Schema supports conditional validation using the if, then, and else keywords. This allows you to apply different validation rules depending on the value of specific fields — a powerful way to encode complex business logic directly in your schema.

{
  "type": "object",
  "properties": {
    "type": { "type": "string", "enum": ["personal", "business"] },
    "companyName": { "type": "string" },
    "firstName": { "type": "string" },
    "lastName": { "type": "string" }
  },
  "if": {
    "properties": {
      "type": { "const": "business" }
    },
    "required": ["type"]
  },
  "then": {
    "required": ["companyName"]
  },
  "else": {
    "required": ["firstName", "lastName"]
  }
}

In this schema, when type is "business", the companyName field becomes required. Otherwise (e.g., when type is "personal"), firstName and lastName are required instead. This pattern is particularly useful for forms and APIs that have different required fields depending on a category or mode selection.

Real-World Example: User Registration API Request Schema

Let's put everything together with a practical example. Below is a comprehensive JSON Schema for validating a user registration API request body:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "UserRegistration",
  "description": "Schema for the user registration API request body",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 20,
      "pattern": "^[a-zA-Z0-9_]+$",
      "description": "Alphanumeric and underscores only, 3-20 characters"
    },
    "email": {
      "type": "string",
      "format": "email",
      "description": "A valid email address"
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "Minimum 8 characters"
    },
    "age": {
      "type": "integer",
      "minimum": 14,
      "maximum": 150,
      "description": "Must be at least 14 years old"
    },
    "role": {
      "type": "string",
      "enum": ["user", "admin", "moderator"],
      "default": "user",
      "description": "The user's role in the system"
    },
    "profile": {
      "type": "object",
      "properties": {
        "displayName": {
          "type": "string",
          "maxLength": 50
        },
        "bio": {
          "type": "string",
          "maxLength": 500
        },
        "avatarUrl": {
          "type": "string",
          "format": "uri"
        }
      },
      "additionalProperties": false
    },
    "interests": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 0,
      "maxItems": 10,
      "uniqueItems": true,
      "description": "List of interests (max 10, no duplicates)"
    },
    "agreedToTerms": {
      "type": "boolean",
      "const": true,
      "description": "Must be true — user must agree to terms of service"
    }
  },
  "required": ["username", "email", "password", "agreedToTerms"],
  "additionalProperties": false
}

This schema enforces the following rules:

  • username: 3-20 characters, alphanumeric and underscores only
  • email: Must be a valid email format
  • password: Minimum 8 characters, maximum 128
  • age: Must be at least 14 (optional field)
  • role: Must be one of "user", "admin", or "moderator"
  • profile: A nested object with displayName, bio, and avatarUrl — no extra properties allowed
  • interests: An array of unique strings, maximum 10 items
  • agreedToTerms: Must be exactly true
  • No additional properties beyond those defined are permitted

Draft Versions

JSON Schema has evolved through multiple draft versions over the years. The latest version is Draft 2020-12. Here is a brief overview of the major drafts and what they introduced:

  • Draft 4 (2013): The first widely adopted stable version. Many older tools and libraries still target this draft.
  • Draft 6 (2017): Added const, contains, propertyNames, and boolean schemas.
  • Draft 7 (2018): Introduced conditional schemas with if/then/else, plus readOnly and writeOnly.
  • Draft 2019-09: Introduced $defs, $anchor, unevaluatedProperties, and the vocabulary system.
  • Draft 2020-12: The current latest version. Introduced prefixItems (replacing the tuple form of items), improved the vocabulary system, and added $dynamicRef/$dynamicAnchor.

For new projects, it is recommended to use Draft 2020-12. You can declare which draft your schema targets by including the $schema keyword at the top of your schema file:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    ...
  }
}

Conclusion

JSON Schema is a powerful tool for ensuring data integrity across a wide range of scenarios — from API request validation and form input checking to configuration file verification and automated documentation generation. Starting with basic keywords like type, properties, and required, you can progressively adopt advanced features like $ref for schema reuse, enum and const for value constraints, and if/then/else for conditional logic.

By defining clear schemas for your data, you catch errors earlier, reduce debugging time, improve team communication, and create self-documenting APIs. JSON Schema is supported by a rich ecosystem of validators, code generators, and documentation tools across virtually every programming language.

Ready to generate and validate JSON Schemas? Try the tool below:

JSON Schema Tool — Automatically generate a JSON Schema from your data, or validate your data against an existing schema. Works right in your browser with no installation required.

JSON Schema

Generate and validate JSON Schema automatically

Try it now

Related Posts