JSON to JSON Schema

Generate a JSON Schema (Draft 2020-12) from a JSON document.

JSON Input
JSON Schema Output
JSON Schema output appears here

Related Tools

Documentation

What is JSON to JSON Schema?

This tool infers a JSON Schema (Draft 2020-12) from a sample JSON document — the same type-inference pass used by every generator in this category (TypeScript, Zod, Go, Java, and the rest), just emitting a schema document instead of a language-specific type declaration.

How it works

The sample is parsed into the same internal type tree every other generator on this site builds from — strings, numbers (split into integer/number), booleans, arrays, and nested objects, each object given a name derived from its key. Each distinct object shape becomes its own entry under $defs, and the root schema is a single $ref into that root object's definition — the same "declare each nested type once, reference it elsewhere" decomposition the TypeScript and Zod generators use, just expressed in JSON Schema's own referencing syntax instead of interface/z.object declarations. Every key present with a non-null value in the sample is added to that object's required array; additionalProperties: false is set on every object, since a single sample defines a closed shape by default — loosen it by hand if your real data legitimately carries extra fields the sample didn't show.

Features

  • Draft 2020-12 output with a $schema declaration
  • Nested objects split into named $defs entries, not one deeply nested blob
  • Integers and floats distinguished (integer vs. number)
  • Present, non-null keys marked required automatically
  • Null values and empty arrays get an honest description instead of a guessed type

Example

Input:

{
  "name": "DevFormats",
  "rating": 4.9,
  "free": true,
  "logo": null,
  "tags": ["json", "yaml"]
}

Output:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/$defs/Root",
  "$defs": {
    "Root": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "rating": { "type": "number" },
        "free": { "type": "boolean" },
        "logo": { "description": "Sample value was null — no type could be inferred." },
        "tags": { "type": "array", "items": { "type": "string" } }
      },
      "required": ["name", "rating", "free", "tags"],
      "additionalProperties": false
    }
  }
}

Common errors

A schema generated from one sample is only as complete as that sample — a field that's sometimes a string and sometimes a number will be typed as whichever it was in your sample, and validating a document where that field holds the other type will fail even though your real API considers both valid. There's no way to fix this from a single input; paste the most representative sample you have, and hand-edit the type keyword to an array (e.g. ["string", "number"]) for any field you know varies.

Best practices

Run the output through JSON Schema Validator against a handful of real documents — including edge cases the original sample didn't cover — before relying on it in a pipeline. additionalProperties: false is the most common thing worth loosening: if your real payloads carry fields beyond what one sample happened to show, either add them explicitly or relax that constraint per object.

Frequently Asked Questions

What happens to a field that was null in my sample?

It gets no "type" keyword at all — just a description noting the sample value was null, so the schema validates any type for that field rather than fabricating a guess like "string" that might be wrong in production data.

What happens to an empty array?

Same honesty policy: an empty array has no element to infer a type from, so its items schema carries only a description explaining why, not a made-up type.

Are nested objects inlined or split into $defs?

Split into $defs, one entry per distinct object shape found in your sample, with the root schema being a single $ref into $defs. That mirrors how every other generator on this site (TypeScript, Zod, Java) declares nested types as separate named declarations rather than one deeply nested blob.

Does the output mark required vs optional fields?

Yes — every key present with a non-null value in your sample is added to that object's "required" array. A key that was null is treated as not required, since a single null sample can't tell you whether the field is always present but nullable, or sometimes absent entirely.