100% local — your data never leaves your browser

JSON to JSON Schema — A Contract for CI

Turn a JSON sample into a JSON Schema, draft 2020-12. Required keys and additionalProperties are switches, so the contract says what you mean.

Instant Private Zero cookies
Indentation

JSON input

JSON Schema output

What this tool does

A JSON sample becomes a JSON Schema in draft 2020-12.

{ "id": 1, "name": "Ada", "address": { "city": "Paris" } }
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "name": { "type": "string" },
    "address": {
      "type": "object",
      "properties": { "city": { "type": "string" } },
      "required": ["city"]
    }
  },
  "required": ["id", "name", "address"]
}

Nested objects are written in place. There is no $defs section and no $ref: for a sample, an inlined schema is the one you can read top to bottom.

Two switches, because both answers are defensible

  • Required keys. On by default: every key of the sample is listed. Off: no required array at all, so a document missing a key still validates.
  • additionalProperties. Permissive by default — an extra key passes. Set it to strict and "additionalProperties": false is added to every object, so an unexpected key is an error.

Neither choice can be read off a sample. They are statements about your API, so they are yours to make rather than ours to guess.

integer and number come from the literal

3 gives integer; 3.0 and 1e3 give number. JSON has a single numeric type, so the way a number was written is the only trace of what produced it. A schema calling 10.0 an integer rejects 10.5, most likely the next record — this tool did exactly that until the defect was found and fixed while writing these pages.

What the sample does not describe

  • "n": null gives {"type": "null"}, a schema accepting nothing else. If the field is a nullable string, {"type": ["string", "null"]} is the edit.
  • An empty array gives {"type": "array"} with no items: nothing is claimed about elements that were never seen.
  • A mixed array gives anyOf, listing exactly the shapes present.
  • No format, no minLength, no pattern. An email, a UUID and a sentence are all "type": "string" here. Adding "format": "email" would be a guess about meaning, not a reading of structure — and it is the first thing worth adding by hand once you know the field.

Private by design

Everything runs locally in your browser with JavaScript. Your data is never uploaded, which makes the tool safe for sensitive content, and it keeps working offline.

Frequently asked questions

Why is everything in `required`?
Because every key was in the sample, and that is the only claim the document supports. It is also a switch: turn it off and no `required` array is emitted at all. Leaving it on gives you a schema that fails loudly on a missing key, which is usually the more useful starting point.
Why is there no `$defs` section?
Because the schema is inlined: nested objects are written where they appear, even if the same shape occurs twice. That reads better for a sample and validates identically. If you are factoring a large schema for reuse, moving repeated subschemas into `$defs` with `$ref` is an edit worth making by hand.
What decides between `integer` and `number`?
The literal. `3` gives `integer`, `3.0` and `1e3` give `number`, because JSON has one numeric type and the written form is the only evidence of the original. A schema that called `10.0` an integer would reject `10.5` — the next record — which is what this tool used to do until it was fixed.

Related converters