JSON Schema Explained for Beginners (With Examples)

Data modeling 10 min readUpdated October 12, 2026

JSON itself says nothing about what a document should contain. Is age a number or a string? Is email required? JSON Schema is a standard way to answer those questions in a machine-checkable form. A schema is just another JSON document that describes the shape of your data, so you can validate input automatically and document your API at the same time.

A first schema

Suppose your API accepts a user like this:

{
  "id": 42,
  "name": "Asha",
  "email": "asha@example.com",
  "roles": ["admin", "beta"]
}

A schema for it looks like this:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "type": "object",
  "properties": {
    "id":    { "type": "integer", "minimum": 1 },
    "name":  { "type": "string", "minLength": 1 },
    "email": { "type": "string", "format": "email" },
    "roles": {
      "type": "array",
      "items": { "type": "string", "enum": ["admin", "editor", "beta"] },
      "uniqueItems": true
    }
  },
  "required": ["id", "name", "email"],
  "additionalProperties": false
}
$schema names the version of the specification the schema is written for

Read it from top to bottom: the document is an object; it may have the four listed properties with the given types and limits; id, name and email must be present; and no other properties are allowed.

The keywords you will use most

KeywordApplies toWhat it does
typeAny valuestring, number, integer, boolean, object, array or null. Can be a list, such as ["string", "null"].
propertiesObjectsDescribes each known key with its own sub-schema.
requiredObjectsLists keys that must be present. Listing a key in properties alone does not make it required.
additionalPropertiesObjectsfalse rejects any key not listed in properties. The default is to allow them.
itemsArraysThe schema every element must match.
minItems, maxItems, uniqueItemsArraysLimit the length, and require distinct elements.
enum, constAny valueRestrict to a list of allowed values, or to exactly one.
minimum, maximumNumbersInclusive limits. exclusiveMinimum and exclusiveMaximum exclude the boundary.
minLength, maxLength, patternStringsLimit length, or require a match with a regular expression.
formatStringsHints such as email, date-time, uri, uuid. Many validators only check them when you turn format validation on.

Two defaults that surprise people

Properties are optional unless listed in required, and extra properties are allowed unless you set additionalProperties to false. A typo such as emial therefore passes a schema that does not forbid extra keys, while the real email is reported missing only if it is required.

Valid and invalid examples

{
  "id": "42",
  "name": "",
  "roles": ["admin", "admin", "root"],
  "nickname": "A"
}
Checked against the schema above, this fails in several ways
  • id is the string "42", not an integer.
  • name is shorter than minLength 1.
  • email is required but missing.
  • roles contains a duplicate and a value ("root") that is not in the enum.
  • nickname is not allowed because additionalProperties is false.

A good validator reports all of these with the path to each problem, so the person who sent the data can fix it in one pass.

Combining and reusing schemas

Real schemas repeat structures. Define them once under $defs and point to them with $ref.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "billing":  { "$ref": "#/$defs/address" },
    "shipping": { "$ref": "#/$defs/address" }
  },
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city":   { "type": "string" },
        "zip":    { "type": "string", "pattern": "^[0-9]{6}
quot; } }, "required": ["street", "city"] } } }

To express choices, use allOf (must match all), anyOf (at least one) and oneOf (exactly one). For a value that may be missing data, allow null explicitly with "type": ["string", "null"].

Validate data in code

Python: jsonschema

# pip install jsonschema
import json
from jsonschema import Draft202012Validator

schema = json.load(open("user.schema.json", encoding="utf-8"))
data = json.load(open("user.json", encoding="utf-8"))

validator = Draft202012Validator(schema)
for error in sorted(validator.iter_errors(data), key=lambda e: [str(part) for part in e.path]):
    location = "/".join(str(part) for part in error.path) or "(root)"
    print(f"{location}: {error.message}")
iter_errors reports every problem, not just the first

JavaScript: Ajv

// npm install ajv ajv-formats
import Ajv2020 from "ajv/dist/2020.js";
import addFormats from "ajv-formats";

const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv); // enables checks for "email", "date-time", and so on

const validate = ajv.compile(schema);
if (!validate(data)) {
  console.log(validate.errors);
}
Use the Ajv2020 build for schemas that declare draft 2020-12

Start from sample data, then tighten

Writing a large schema by hand is slow, so it is common to generate a first draft from a sample document and then edit it. A generator can see the types in your sample, but it cannot know your rules. A sample with one string field says nothing about whether the field is required, how long it may be, or whether it is really one of a fixed set of values.

  1. Generate a draft from a representative sample, ideally the most complete one you have.
  2. Decide which properties are truly required and remove the rest from required.
  3. Add limits such as minimum, maxLength, pattern and enum where your business rules say so.
  4. Set additionalProperties deliberately, false for strict inputs and the default for forward-compatible ones.
  5. Test the schema against valid and invalid examples, including empty arrays, nulls and boundary values.

Where schemas are used

  • API contracts. OpenAPI 3.1 uses JSON Schema to describe request and response bodies.
  • Input validation. Reject bad data at the edge of your system with a clear message.
  • Configuration files. Editors can use a schema to offer autocomplete and flag mistakes while you type.
  • Test data and documentation. The schema is a precise, shared definition of a data format that both humans and tools can read.

Frequently asked questions

Which JSON Schema version should I use?

Draft 2020-12 is the current version of the specification and a good default for new work. Draft-07 is still widely supported by older tools. Always include $schema so validators know which rules to apply.

Is JSON Schema the same as an OpenAPI schema?

They are closely related. OpenAPI 3.1 aligns with JSON Schema 2020-12, while OpenAPI 3.0 used a modified subset with some differences, such as how nullable values are written.

Does JSON Schema check business rules?

Only the ones that can be expressed as structure and limits. Rules that depend on other data, such as "this id must exist in the database" or "end date must be after start date", still need code.

Why does my `format: email` check not fail on a bad address?

In the specification, format is an annotation unless format validation is enabled. Turn it on in your validator, for example with ajv-formats in Ajv, and remember that format checks are approximate by nature.

Related guides

See all 12 guides

© 2026 TrueJson. All rights reserved.