Skip to main content
Convert2JSON

JSON Schema examples

Schemas that do something, from a five-line object check up to conditionals and reusable definitions.

Last reviewed

A minimal object schema

Two things to note. `required` is a list of names, not a flag on each property — a property being defined does not make it required. And `additionalProperties: false` is what turns the schema from a minimum bar into a contract; without it, any extra field passes.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["id", "email"],
  "properties": {
    "id":    { "type": "integer", "minimum": 1 },
    "email": { "type": "string", "format": "email" },
    "name":  { "type": "string", "maxLength": 120 }
  },
  "additionalProperties": false
}

Nullable fields

JSON Schema has no `nullable` keyword. A field that may be null is a union of types.

{
  "properties": {
    "retiredOn": { "type": ["string", "null"], "format": "date" }
  }
}

Enums and constants

{
  "properties": {
    "status":  { "enum": ["draft", "active", "archived"] },
    "version": { "const": 2 }
  }
}

Arrays

`items` constrains every element. `prefixItems` with `items: false` describes a fixed-length tuple — in drafts before 2020-12 this was written as an array-valued `items`, which is the most common incompatibility between draft versions.

{
  "properties": {
    "tags": {
      "type": "array",
      "items": { "type": "string", "minLength": 1 },
      "minItems": 1,
      "uniqueItems": true
    },
    "point": {
      "type": "array",
      "prefixItems": [{ "type": "number" }, { "type": "number" }],
      "items": false
    }
  }
}

Reusable definitions

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {
    "address": {
      "type": "object",
      "required": ["city", "country"],
      "properties": {
        "city":    { "type": "string" },
        "country": { "type": "string", "pattern": "^[A-Z]{2}$" }
      }
    }
  },
  "type": "object",
  "properties": {
    "billing":  { "$ref": "#/$defs/address" },
    "shipping": { "$ref": "#/$defs/address" }
  }
}

Conditional requirements

if/then/else expresses "when this field has this value, these other fields are required" — the rule that otherwise ends up duplicated in application code.

{
  "type": "object",
  "properties": {
    "method": { "enum": ["card", "invoice"] },
    "cardLast4": { "type": "string", "pattern": "^[0-9]{4}$" },
    "poNumber":  { "type": "string" }
  },
  "if":   { "properties": { "method": { "const": "card" } } },
  "then": { "required": ["cardLast4"] },
  "else": { "required": ["poNumber"] }
}

What a validation failure looks like

Errors are reported as a JSON Pointer into the document plus the keyword that failed. That pointer is what lets an editor jump to the offending line rather than making you search for it.

/email        must match format "email"
/tags/1       must NOT have fewer than 1 characters
/             must have required property 'id'
/status       must be equal to one of the allowed values

Generating a first draft

Inferring a schema from a real payload gets the structure right in seconds. It cannot infer intent: everything present becomes required, formats are guessed from shape, and an enum looks like a plain string. Generate, then tighten — the generated draft is a starting point, not a contract.

Keep reading

  • JSONPath examplesOne sample document, and the expressions people actually need against it, each with the result it produces.
  • JSON API response examplesThe response shapes you meet in practice, and what each convention costs the client that consumes it.