Generate a JSON Schema from a sample
Runs locallyInfer a draft 2020-12 JSON Schema from a sample payload.
JSON input
Generated schema
What a generated schema gets right, and what you have to fix by hand
Inference reads one sample and describes exactly that sample. It gives you the skeleton — types, nesting, property names — in seconds, which is the tedious part. What it cannot know is the difference between a field that happened to be present and a field that is always present, or between a string and a date. If what you need is code rather than a schema, generate typed models from the same sample.
Treat the output as a first draft: generate, then prune the required list, widen the types that can be null, and add the formats and constraints that carry the real rules.
Sample payload
{
"id": 4021,
"email": "[email protected]",
"createdAt": "2026-09-15T09:00:00Z",
"score": 4,
"tags": [],
"manager": null
}Inferred schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "integer" },
"email": { "type": "string" },
"createdAt": { "type": "string" },
"score": { "type": "integer" },
"tags": { "type": "array", "items": {} },
"manager": { "type": "null" }
},
"required": [
"id", "email", "createdAt",
"score", "tags", "manager"
]
}Four things in that output are wrong for real traffic: score is an integer only because this sample had no decimal, tags has no element type because the array was empty, createdAt is a plain string, and manager is typed null forever.
Where people get caught
Every key in the sample lands in required
A field that is optional in real traffic will be marked required, and the first payload that legitimately omits it fails validation. Pruning required is the first edit to make, every time.
An empty array tells the generator nothing
"tags": [] produces items: {}, which accepts anything. Feed a sample with at least one element of every array, or write the item schema yourself.
null becomes a type, not a possibility
A field that was null in the sample is typed "null". What you almost always want is ["string", "null"] — nullable, not always-null.
Whole numbers become integers
A price that happened to be 4 in the sample is typed integer, and 4.5 then fails. If a field can be fractional, widen it to number by hand.
Formats cannot be inferred safely
An ISO-8601 timestamp, a UUID and an email are all just strings. Adding "format": "date-time" / "uuid" / "email" is manual, and it is where most of the value of a schema actually lives.
The draft you target changes the keywords
Tuple validation moved from items: [...] in draft-07 to prefixItems in 2020-12, and $id / definitions were renamed. A schema pasted into a validator running a different draft can silently stop enforcing what you meant.
About the JSON Schema generator
How it works in 4 steps · 4 common use cases · 3 questions answered
About the JSON Schema generator
How it works in 4 steps · 4 common use cases · 3 questions answered
How it works
- 1.Paste a representative sample document — the schema can only describe what the sample shows.
- 2.A draft 2020-12 schema is inferred: property types, required lists and array item types.
- 3.Strings that look like ISO date-times or email addresses are given a format hint.
- 4.Copy the schema and refine it — add constraints, descriptions and enums by hand.
Common use cases
- •Bootstrapping a request-body schema for an OpenAPI specification
- •Generating a contract to validate incoming webhooks against
- •Documenting the shape of a legacy response nobody wrote down
- •Producing a starting point for a JSON Schema based test fixture
FAQ
Is the generated schema ready to use as a contract?
Treat it as a first draft. It captures structure and types faithfully, but it cannot know which fields are genuinely optional, what ranges are valid, or which strings are really enums — that judgement has to be added by you.
How are required fields decided?
Every key present in the sample is marked required. If a field is optional in reality, remove it from the required list after generating.
Which draft does it target?
Draft 2020-12, the current version, which is what OpenAPI 3.1 aligns with.