JSON Schema Generator

Build a draft JSON Schema from a JSON sample: field types, required keys, nested objects and arrays. Pick a draft, copy the result, download schema.json.

Everything runs in your browser — your data is never sent to any server.

Why turn a JSON sample into a schema

Sooner or later, once an API or a config file starts speaking JSON, somebody asks how to describe that format in a way that can actually be checked. Writing a schema from scratch against documentation is slow. Documenting the other direction is easier when you start from a single server response: paste it in, look at what comes out, and you have a first draft. That draft shows the structure, the field names, and which keys always show up versus which ones only sometimes. From there you can do real work: validate responses, drive form fields in an editor, generate client-side types. The catch is worth stating plainly: a generator describes what it saw, not what was intended, so the result nearly always needs a human pass.

What the schema generator does

  • Detects string, number, integer, boolean, null, array and object types
  • Expands nested objects and arrays recursively, with no depth limit
  • Marks a field required only when the key appears in every object of the sample
  • Lists every field and lets you attach your own description to each
  • Switches between draft-07, 2019-09 and 2020-12, and can add additionalProperties: false

How to get a schema

  1. Paste a JSON sample into the field: an object or an array of same-shaped objects
  2. Pick the specification draft and decide whether extra fields should be rejected
  3. Press "Build schema" and read the generated JSON
  4. Fill in the descriptions and rebuild if you need to adjust it

How the sample is parsed

Every value is first classified by type: a whole number differs from a fractional one, null counts as its own type, and arrays and objects are recognised by their shape rather than their contents. Next, matching keys from several objects are merged into a single property, and for each one the generator records whether the key showed up in every sample: only those end up in required. Nested objects and array elements are handled by the same routine, so the schema grows together with the data. Mixed types get special attention too: if a spot holds both a string and null, the schema gets a list of types instead of one preferred type. The whole computation is a single pass over the input JSON and runs entirely in the browser.

Examples: which type comes out and how it looks in the schema

Value in JSONType in schemaComment
"name": "Ivan"stringAny string, the format is not checked
"id": 42integerA whole number with no fractional part
"price": 199.5numberA fractional number, integer would not fit
"active": truebooleanExactly two values: true and false
"note": nullnullIts own type, not a string and not an empty field
"tags": ["a", "b"]array with string itemsThe element type is inferred from the data
"user": { "id": 1 }object with propertiesThe nested object is expanded recursively
"value": "7" in one record, 7 in another[string, integer]A mixed type, so the schema lists both
key present in 3 records out of 3requiredThe field shows up in every object of the array
key present in 2 records out of 3properties onlyThe field is optional and a validator will not demand it
"count": 0integerZero is a real value, not an empty one
empty array []array without itemsThe element type is unknown, constraints are added by hand

Types are inferred from the values themselves, so the same key in different records can end up with different types.

Where a schema like this actually earns its keep

The first scenario is a contract between a frontend and a backend. Someone builds a form from a sample response, and a month later a validation error arrives for a field nobody ever discussed. A draft schema kept next to that sample turns a silent assumption into an explicit list of fields, and the mismatch becomes visible immediately. The second scenario is generating types for a client: the structure under properties turns into an interface or a TypeScript type, and the editor starts suggesting fields while you type.

The third scenario is checking config and data files. If a service reads YAML or JSON configuration, a schema derived from a sample is handy to keep alongside and to run every file through at startup. A typo in a key or a missing mandatory field gets caught before the service breaks in production. The fourth is documentation: the same schema works as an appendix to an API description because it shows types, nesting and requiredness in a machine-readable form. Next to a walkthrough of how a URL breaks into parts it answers most of a beginner's questions.

  • A format agreement between two teams
  • Form templates and hints in a code editor
  • Validation of config files when a service starts
  • A machine-readable description of a format in the docs
  • Generating TypeScript types from a response structure
  • Regression checks on a response shape after backend changes

Mistakes that produce a wrong schema

The most common mistake is treating a draft as a finished contract. A schema built from one sample looks solid: types are in place, required is filled, the structure is tidy. What it lacks is ranges, formats, enums and descriptions, and that creates an illusion of completeness. The second mistake is over-engineering types: if a field arrived as a string in the sample, should the schema forbid numbers? The strict answer depends on the server rather than the sample, and such decisions are better made explicitly than inherited from a single response.

The third mistake is not noticing mixed types. A field that arrives as a number in some records and a string in others produces a list of types in the schema, and that is not a generator failure but a warning about a real problem on the server. The fourth is forgetting nesting: if an object holds an array of objects, the required inside items follows its own logic, and it is easy to miss when editing by hand. The fifth is leaving descriptions empty, which means that someone reading the schema in six months will have no idea what a field is for. For more on formats and data structures, the piece on JSON and XML helps.

  • Mistaking a draft for a complete contract
  • Inheriting type strictness from a single sample
  • Ignoring mixed types in the same field
  • Forgetting required inside nested arrays
  • Leaving descriptions blank
  • Noticing fields only after the sample missed them

Walking through a sample step by step

Take a small response: an array of two objects where the first one has a note field and the second does not. The generator sees two objects, merges their keys, and counts for each key how many times it appeared. The keys id and title appeared twice out of two, so they went into required. The key note appeared once, so it lives in properties but not in required. The type of note came out as null, and that is honest: the sample held exactly null there.

Nested objects and array elements are parsed the same way: the type of a value is established first, then the keys of all encountered objects are merged, and only after that is required computed. The order matters, because required is not a property of an individual field but a conclusion about whether a key shows up in every record. That is also why a sample of a single object produces a schema where every field is mandatory: there is nothing to compare against.

What happens at each parsing step

StepActionResult
1Type detectionA value is classified as string, number, integer, boolean, null, array or object
2Key mergingMatching keys from several objects are collected into one property
3CountingFor every key the generator counts how many objects contain it
4Required decisionA key found in every object ends up in required
5RecursionNested objects and array elements run through the same algorithm
6Mixed typesDifferent types in one field produce a list of types in the schema
7DescriptionsThe descriptions you typed are inserted into the matching nodes
8Assembly$schema, properties and additionalProperties are added to the nodes

Parsing is a single pass over the input JSON and runs entirely in the browser: the sample is never sent anywhere.

What to do with the draft next

The first step after generating is to read the schema yourself and fix it by hand. Three things deserve a look: mandatory fields that do not always arrive, types the server changes from time to time, and descriptions that do not exist at all. The second step is to run the schema through the validator you will actually use in the project, against several real responses. That exposes the gap between expectation and what the server really sends and saves you from surprises in production.

The third step is to keep the schema in the repository next to the code that uses it and to update it whenever the format changes. A schema living apart from the code goes stale first. If your project is a monorepo or generates types, it helps to see how JSON to TypeScript conversion and diffing two JSON documents work: the difference shows which fields appeared and which disappeared after a server-side change.

  • Read the schema yourself and fix it by hand
  • Validate it with the same validator the project uses
  • Run it against several real responses
  • Add descriptions and constraints wherever you know them
  • Keep the schema next to the code and update both together

Frequently asked questions

How is a generated schema different from a hand-written one

A hand-written schema describes a contract: the author knows which fields exist, which ones are mandatory, and what ranges numbers fall into. A generator assembles a description from one concrete chunk of data and sees only what happened to be in that chunk. The difference shows up in a simple case: if the sample has no price field, the schema will contain neither price nor any hint that it is mandatory. So treat the generator output as a first draft. It saves you the tedium of initial markup, but it does not replace reading the documentation or agreeing on the contract with whoever produces the data.

Why did my field not make it into required

Because the key was not present in every object of the sample. If you pasted an array of three records and one of them lacks the field, it lands in properties but not in required: the schema honestly says the field is optional. For an array holding a single object, every key ends up required, because "in every object" holds trivially. If the field really is mandatory but sometimes missing from your sample, add it to required by hand. Otherwise a validator will happily accept a record that lacks it.

What is the difference between integer and number in the output

The type integer means a whole number: 42 fits, 42.5 does not. The type number means any number, fractional ones included. The parser looks at the actual value: a sample of 1 produces integer, a sample of 1.5 produces number. Mixed cases are possible too, such as an identifier field where the server sometimes sends the string "7" and sometimes the number 7. The type is then inferred as a list, and the schema contains something like type: [string, integer]. That is usually a sign the server should normalise the format on its side.

Why would you turn on additionalProperties: false

JSON Schema allows any extra fields in an object by default, even ones absent from properties, so a validator says "fine" and lets a typo in a field name slip through. The additionalProperties: false flag closes that door and turns the schema into a strict contract. The price of strictness is obvious: the moment the server starts sending a new field, every response fails validation until the schema is updated. For a draft schema built from a sample, the flag is useful because it surfaces mismatches between expectation and reality right away.

Which specification draft should I pick

For most validators, draft-07 is enough: libraries from Java to Python understand it, it lives inside many editors and validation tools, and it is the version people meet first. The 2019-09 and 2020-12 drafts are newer and more precise about vocabulary, but older validators support them less often. The choice changes the $schema line at the top of the file and a few spellings such as exclusiveMinimum, which is written differently across versions. When in doubt, take draft-07 and check the result with the same validator your project will actually use.

Can I build a schema from a single response

You can, and it is a normal first step, but a single answer says nothing about variability. One response always describes one state: no optional fields, no empty arrays, no fields arriving with different types. If you can gather several responses, put them in an array: the generator will merge them and show exactly which keys always appear and which do not. For a broader look at how to read data structures, see the piece on data formats and ISO timestamps.

The schema does not describe date or email formats - why

Because a sample only reveals that there is a string there. You can guess the format behind "2026-03-14", but the format behind "14.03.2026" you cannot, and any guess would be wrong. The format keyword in JSON Schema checks the shape of the data rather than its contents, and validators differ on how far they take it: some only check base64, others consult their own extra rules. Those constraints are added by hand, and dedicated tools such as the JSON Schema validator exist for that job.

How does this differ from online schema builders

The main difference is that everything here is computed in the browser. Your sample never leaves the machine, and the generated schema is not published into a shared catalogue or attached to somebody else's project. The second difference is predictability: the generator describes exactly what it saw and says so plainly instead of guessing formats. The trade-off is that there is no cleverness involved. It will not work out that price is in rubles or that createdAt holds a Unix timestamp in seconds. That trade is deliberate: speed and privacy instead of guesses.

Related tools