Starting a schema from an example
Writing a JSON Schema from scratch is slow, and most people already have example payloads. Generating a first draft from a sample gives you the full structure — every nested object, every array item type, which keys are always present — in seconds. You then tighten it by hand: add enums, minimums, patterns and descriptions. Typical uses are validating webhook or API payloads with Ajv, documenting request bodies in OpenAPI 3.1, and enabling autocompletion for a config file in VS Code. New to the vocabulary? Read JSON Schema basics.
What is inferred
- type for every value:
object,array,string,boolean,null, andintegerversusnumberdecided by how the number is written —42is an integer,42.0and4.2e1are numbers. A position holding both becomesnumber. - properties for every object, in the original key order, nested as deep as the data goes.
- items for arrays. All elements are merged into one item schema, so the schema describes every element rather than just the first one. Empty arrays get no
items. - Mixed types at the same position become a type array, for instance
"type": ["string", "null"]for a field that is sometimes null. This is how nullable fields appear.
The output never contains additionalProperties, enum, minimum or pattern; one sample cannot justify those constraints, so you add them deliberately.
Options
Draft selects 2020-12 (the default, used by OpenAPI 3.1) or Draft-07 (still the most widely supported by older validators). It sets the $schema URL; the keywords generated are valid in both drafts.
Mark present properties as required (on by default) adds a required list to each object. Inside arrays, a key is required only if every object at that position has it, so optional keys stay optional. Turn it off for a permissive schema in which every property is optional.
Detect string formats (date-time, email, uri…) (on by default) adds format when all strings at a position match the same format: date-time (with a T and a time zone), date, time, uuid, ipv4, ipv6, email or uri (with scheme://). Detection is deliberately stricter than validation, and every claimed format passes the same checks as Ajv’s ajv-formats package, so the schema always validates its own sample. If strings at one position disagree, no format is set.
Tips
Give the generator several representative records — an array of real objects with and without optional fields — because required and nullability come from comparing them. Remember that formats are only annotations unless your validator enables format assertion (in Ajv, add ajv-formats). Pair the schema with types from JSON to TypeScript, and check payloads by hand in the JSON validator. Nothing you paste is uploaded.
Examples
User record with formats
Detects email, uri and date-time formats, types id as integer and score as number, and marks every key as required.
{
"id": 1042,
"name": "Aisha Tan",
"email": "aisha.tan@example.com",
"website": "https://aisha.example.com",
"createdAt": "2024-03-11T09:30:00Z",
"score": 98.5,
"tags": ["admin", "beta"],
"address": { "city": "Singapore", "postcode": "018956" }
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"website": {
"type": "string",
"format": "uri"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"score": {
"type": "number"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"address": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"postcode": {
"type": "string"
}
},
"required": [
"city",
"postcode"
]
}
},
"required": [
"id",
"name",
"email",
"website",
"createdAt",
"score",
"tags",
"address"
]
}
Array of orders with optional and nullable fields
coupon becomes a string-or-null type, giftNote is left out of required because one order lacks it, and $schema points at draft-07.
[
{ "id": "ord_1", "total": 129.9, "paid": true, "coupon": null },
{ "id": "ord_2", "total": 79, "paid": false, "coupon": "SPRING10", "giftNote": "Happy birthday" }
]{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"total": {
"type": "number"
},
"paid": {
"type": "boolean"
},
"coupon": {
"type": [
"string",
"null"
]
},
"giftNote": {
"type": "string"
}
},
"required": [
"id",
"total",
"paid",
"coupon"
]
}
}
Permissive schema without formats
With both options off, the schema only describes types, so every property is optional and the IP addresses carry no ipv4 format.
{
"host": "10.0.0.12",
"port": 5432,
"replicas": ["10.0.0.13", "10.0.0.14"],
"ssl": true
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"host": {
"type": "string"
},
"port": {
"type": "integer"
},
"replicas": {
"type": "array",
"items": {
"type": "string"
}
},
"ssl": {
"type": "boolean"
}
}
}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Trailing comma before '}'Explained | The sample has a comma after its last property, which strict JSON rejects. | Remove the comma; the JSON formatter can repair it automatically. |
The JSON is nested more than 500 levels deep | The sample is pathologically deep, usually a recursive structure serialised without limit. | Shorten the sample to a few levels of nesting. |
Duplicate key "…" — most parsers keep only the last valueExplained | A warning: an object repeats a key. Both values are used to infer that property’s type. | Remove the duplicate from the sample if it is a mistake. |
Frequently asked questions
Which draft should I choose?
Use 2020-12 for new projects and OpenAPI 3.1. Choose draft-07 if your validator or tooling does not support 2020-12 yet.
How are optional fields detected?
Within arrays of objects, a property is required only when every object has it. With a single object, every present key is required unless you switch that option off.
Why did my date string not get a format?
Formats are only added when every string at that position matches. A date-time also needs a T separator and a time zone, such as 2024-03-11T09:30:00Z.
Does the schema forbid extra properties?
No. additionalProperties is not set, so unknown keys are allowed. Add “additionalProperties”: false yourself if you want strict objects.
Is my JSON sent anywhere?
No. The schema is inferred by code running in your browser.