JSON Schema Generator

Turn a sample document into a JSON Schema you can validate against. The generator reads the shape, tags common string formats such as email and date-time, and marks every key that appears in all sample objects as required. You then add the ranges, enums and lengths by hand, since a sample carries none of them.

JSON Input
Generated Code

1 JSON Schema Generator example

JSON sample

1
2
3
4
5
6
7
{
  "id": 1,
  "name": "Ana",
  "orders": [
    { "order_id": 1001, "note": "gift" },
    { "order_id": 1002 }
  ]
}

Generated schema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string"
    },
    "orders": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "integer"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "order_id"
        ]
      }
    }
  },
  "required": [
    "id",
    "name",
    "orders"
  ]
}

2 What it can and cannot know

Types and structure

Reliable. Objects, arrays, nested shapes and the type of every leaf come straight from the data.

Required keys

A guess. The generator marks a key required when it appears in every sample object. If your sample happened to include an optional field every time, the schema now insists on it, so review this list first.

String formats

Matched by pattern: date-time, date, time, email, uuid, uri and ipv4. However, a string that looks like a date is not always meant to be one. For example, a version field of 2024-01-15 gets format: date.

Everything about intent

Ranges, enums, string lengths, mutually exclusive fields and defaults. The sample holds none of this, so the schema has none of it either.

3 Draft 2020-12 or draft-07?

Use 2020-12 unless a dependency requires draft-07. OpenAPI 3.1 adopted 2020-12, so a 3.1 spec can reference the output directly. Ajv supports it through its Ajv2020 class (the default Ajv export is draft-07). Draft-07 stays in the dropdown because many existing projects are pinned to it, and migrating only for the new draft rarely pays off.

OpenAPI 3.0 fits neither draft cleanly. It uses its own dialect with nullable: true instead of a type union, and treats exclusiveMinimum as a boolean. Generate here, then adjust those two by hand.

How to use the JSON Schema Generator tool

  1. Paste a representative JSON document into the JSON Input panel, or click Upload File. A sample that includes every optional field produces a more complete schema.
  2. Set Title, and pick the Draft: 2020-12 unless a dependency requires draft-07.
  3. Leave Infer formats on to tag date-time, email, uuid and uri strings. Tick No extra props to add additionalProperties: false.
  4. Read the required array before you click Copy Result or Download. It is the field most likely to be wrong.

How to validate against a JSON Schema

JavaScript / Node.js (Ajv)

// npm i ajv ajv-formats
const Ajv = require("ajv");
const addFormats = require("ajv-formats");

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);   // without this, "format": "email" is ignored entirely

const validate = ajv.compile(require("./schema.json"));
const data = require("./payload.json");

if (!validate(data)) {
    for (const e of validate.errors) {
        console.error(`${e.instancePath || "/"} ${e.message}`);
    }
}

Without ajv-formats, Ajv treats format as an annotation, so a schema that appears to check email addresses accepts any string. For a 2020-12 schema, import Ajv from "ajv/dist/2020"; the default Ajv class targets draft-07 and rejects the 2020-12 $schema URI.

Python

# pip install jsonschema
import json
from jsonschema import Draft202012Validator

schema = json.load(open("schema.json"))
data = json.load(open("payload.json"))

validator = Draft202012Validator(schema)
for error in sorted(validator.iter_errors(data), key=lambda e: e.path):
    path = "/".join(str(p) for p in error.absolute_path) or "(root)"
    print(f"{path}: {error.message}")

In CI

# Validate every fixture against the schema on each push
npx ajv-cli validate -s schema.json -d "fixtures/*.json" --all-errors

# Check the schema itself is a valid schema
npx ajv-cli compile -s schema.json

# Useful as a contract test: if the API team changes a response,
# the fixture stops validating and the build tells you.

Common errors and how to fix them

The schema requires a field that is optional in your API
The generator infers required from the sample and marks any key present in every object. Delete the key from the required array if the sample was not representative.
format: email accepts obviously invalid addresses
Formats are annotations by default. Add ajv-formats in JavaScript, or pass a FormatChecker in Python, to make them validate.
additionalProperties: false rejects a valid payload
The API added a field. That strictness is a trade: it catches typos and also fails on every upstream addition. Leave No extra props off for responses you do not control.
OpenAPI 3.0 rejects the schema
OpenAPI 3.0 uses its own dialect: nullable: true instead of a type union, and exclusiveMinimum as a boolean. OpenAPI 3.1 uses JSON Schema 2020-12 and accepts this output directly.

Good to know

A generated schema describes one sample. It has no ranges, enums or string lengths, and no rule that says exactly one of two fields must be present. Those constraints catch most real bugs, and you add all of them by hand. Use the output for the repetitive type and property declarations, then spend your time on the rules.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Which draft does it produce?

Draft 2020-12 by default, which is the dialect OpenAPI 3.1 uses and the one Ajv supports through its Ajv2020 class. Draft-07 is in the dropdown because many existing projects are pinned to it.

How does it decide what is required?

A key present in every sample object is required, and a key present in only some is not. That rule guesses from one sample, so read the required array before you ship the schema. It is the field most likely to be wrong.

Does it infer formats like email or date-time?

Yes, by pattern: date-time, date, time, email, uuid, uri and ipv4. For example, 2026-09-10T08:15:00Z gets format: date-time. Untick Infer formats if you would rather start from plain strings and add each constraint yourself.

Can I use the result for OpenAPI?

Yes for OpenAPI 3.1, which uses draft 2020-12, so the output drops in directly. OpenAPI 3.0 uses an older dialect that differs mainly on nullable and exclusiveMinimum, so adjust those two by hand.

Is a generated schema good enough to validate against?

Treat it as a starting point. It describes the shape of the sample you gave it and nothing about your intent, so it has no ranges, enums, string lengths or cross-field rules. Generate it, then add those constraints by hand where correctness matters.

Related

If you want types instead of a contract, the same sample produces a TypeScript interface, a Go struct or a Python model. To see what changed between two payloads, use the JSON diff.

More Data Converters

Browse all data converters

Copied to clipboard!