JSON is great at carrying data, but it makes no promises about what that data contains. A field your code expects to be a number might arrive as a string, a required key might be missing entirely, and nothing in plain JSON will warn you until something breaks downstream. That is the gap JSON Schema fills: it is a way to describe the shape your data must have, and then automatically check real data against that description.

If you are still getting comfortable with the format itself, our plain-English guide to JSON and the JSON syntax rules explained are good companions. This article assumes you know what an object and an array look like, and focuses on how to validate them.

What Is JSON Schema?

JSON Schema is a vocabulary, itself written in JSON, that lets you annotate and validate JSON documents. Instead of describing your data in prose ("the user object needs an email and an age"), you describe it in a machine-readable schema. A validator then takes two inputs, your schema and a JSON document, and answers one question: does this document satisfy the rules?

Because the schema is just JSON, it travels well. You can store it in your repo, ship it with an API, share it between a frontend and backend, and feed it to tooling that generates documentation, forms, and type definitions. The current widely-used release is draft 2020-12, and validators such as Ajv (JavaScript), jsonschema (Python), and many others implement it.

Think of JSON as the data and JSON Schema as the contract. The contract does not move the data; it tells you whether the data is allowed.

Why Validate JSON at All?

Unvalidated JSON is one of the quietest sources of bugs. A typo in a key name, a boolean sent as the string 'true', or an empty array where one item was required can pass straight through parsing and only surface later as a confusing error. Many of these issues overlap with the common JSON mistakes that break code, and they are far cheaper to catch at the boundary than deep inside your business logic.

  • API request and response checking so a malformed payload is rejected with a clear message instead of corrupting state.
  • Configuration files where a missing or mistyped option should fail loudly at startup.
  • Data pipelines that ingest records from many sources and need every record to match an agreed structure.
  • Documentation and contracts between teams, because the schema doubles as a precise, always-current spec.

Validation is different from formatting. A free JSON formatter & validator confirms your JSON is syntactically valid, well-formed text a parser can read. JSON Schema goes a step further and checks whether the data is structurally valid for your use case.

How JSON Schema Validation Works

A schema is built from keywords. Each keyword asserts something about the data, and the document is valid only if every assertion passes. The most fundamental keyword is type, which constrains the data to one of seven JSON types.

Schema typeMatchesExample value
stringText'hello'
numberAny numeric value3.14
integerWhole numbers only42
booleanTrue or falsetrue
objectKey/value collections{ }
arrayOrdered lists[ ]
nullThe null valuenull

From there you layer on more specific keywords depending on the type you are describing.

Keywords for objects

  • properties defines the schema for each named field.
  • required lists the keys that must be present.
  • additionalProperties controls whether extra, undeclared keys are allowed.

Keywords for strings and numbers

  • minLength, maxLength, and pattern (a regular expression) constrain strings.
  • minimum, maximum, and multipleOf constrain numbers.
  • enum restricts a value to a fixed list of allowed options.

Keywords for arrays

  • items applies a schema to every element in the array.
  • minItems and maxItems bound the length.
  • uniqueItems forbids duplicate elements.

A Complete JSON Schema Example

Suppose your API accepts a user signup. You want an object with a required username (at least three characters), a required email, an optional age that must be a non-negative integer, and a role limited to a known set. Here is a schema that expresses all of that.

{ 'type': 'object', 'properties': { 'username': { 'type': 'string', 'minLength': 3 }, 'email': { 'type': 'string', 'format': 'email' }, 'age': { 'type': 'integer', 'minimum': 0 }, 'role': { 'type': 'string', 'enum': ['admin', 'editor', 'viewer'] } }, 'required': ['username', 'email'], 'additionalProperties': false }

Now compare two documents against it. This first one passes every rule:

{ 'username': 'jordan', 'email': 'jordan@example.com', 'role': 'editor' }

The next one fails for several reasons at once: username is too short, email is missing, age is the wrong type, and signup_source is an extra property the schema does not permit.

{ 'username': 'jo', 'age': 'thirty', 'role': 'editor', 'signup_source': 'ads' }

A validator reports each violation separately, which is exactly what makes schemas useful for clear error messages. Note that format (like 'email' or 'date-time') is an annotation that some validators enforce and others treat as advisory, so confirm how your library handles it before relying on it as a hard check.

Running a Validator in Code

You rarely check schemas by hand. A library compiles the schema once and validates many documents against it. In JavaScript with Ajv, the flow looks like this:

import Ajv from 'ajv'; const ajv = new Ajv(); const validate = ajv.compile(schema); const ok = validate(data); if (!ok) console.log(validate.errors);

The same pattern exists across languages: load the schema, compile or build a validator, then call it on incoming data and inspect the list of errors. Because the schema is shared data rather than code, your frontend and backend can validate against the identical contract, which removes a whole class of mismatched-expectation bugs.

Schema vs Parse Errors: Two Different Checks

It helps to keep two failure modes straight, because they happen at different stages.

CheckWhat it catchesTool
ParsingBroken syntax: trailing commas, unquoted keys, mismatched bracketsJSON parser / formatter
Schema validationValid JSON with the wrong structure, types, or missing fieldsJSON Schema validator

If your data will not even parse, schema validation never gets a chance to run, so fix syntax first. Our guide to fixing "Unexpected token" and other parse errors covers that earlier stage. Once the JSON parses cleanly, JSON Schema takes over to enforce meaning.

Tips for Writing Good Schemas

  • Start loose, then tighten. Begin with type and required, confirm real data passes, and add constraints like pattern and enum incrementally.
  • Decide on extra properties deliberately. Setting additionalProperties to false is strict and safe, but it can break clients that add new fields, so choose based on how your API evolves.
  • Reuse with $ref. Define a sub-schema once (an address, a money amount) and reference it everywhere to avoid drift.
  • Declare the dialect. Add a $schema keyword so validators know which draft you target, for example draft 2020-12.
  • Version your schemas the way you version an API, since a stricter schema is a breaking change for existing data.

Key Takeaways

JSON Schema turns implicit assumptions about your data into explicit, checkable rules. The core idea is small: describe the expected structure with keywords like type, properties, required, and enum, then let a validator compare real documents against that description.

  • JSON Schema is itself JSON, so it is portable and shareable across teams and languages.
  • Validation catches type errors, missing fields, and unexpected keys before they reach your logic.
  • It is separate from parsing and from formatting, which only confirm that text is well-formed.
  • A handful of keywords covers most real-world needs, and you can layer in stricter rules over time.

If you are weighing data formats more broadly, see JSON vs XML vs YAML to understand where schemas fit alongside other validation approaches. Add a schema to your most important payloads first, and you will spend far less time debugging mysterious data problems later.