jsontoolskit.org
JSON and JSON Schema utilities, in the browser
Say hi →

JSON Schema to Markdown

one table per object · follows $ref · constraints, defaults, examples · updated 25 August 2026

A JSON Schema is already the specification — what it is not is readable. This walks the schema and emits Markdown: a section per object, a table row per field, with its type, whether it is required, every constraint that applies, the default and the description. $ref pointers inside the document are followed, so a $defs-heavy schema comes out as a set of linked sections rather than a maze of pointers you have to hold in your head.

Paste input to start.

How to document a schema

  1. Paste the schema, or drop a .json file onto the left pane.
  2. Pick the top heading level to match where the output is going — ## for a section inside an existing README, # for a standalone page.
  3. Turn off the Constraints and Default columns for a narrow table that reads well on a docs site; leave them on for a reference page that has to be complete.
  4. Copy the Markdown into your README, wiki or docs generator. The anchors are GitHub-style slugs, so the cross-links between sections work as-is on GitHub, GitLab and most static site generators.

What ends up in each column

How $ref is handled

A pointer into the same document — #/$defs/Profile, #/definitions/Address, or any other JSON Pointer — is resolved and rendered as its own section, with the field's Type cell linking to it. That is what keeps the output readable: expanding every reference inline duplicates the same table wherever a type is reused, and a recursive schema (a comment with replies, a tree node) would never terminate.

A $ref that points outside the document cannot be resolved here, and rather than rendering it as an empty object the pointer is printed literally and counted in the status line. Run the schema through Bundle $refs first to inline the external ones, then come back.

Definitions that nothing references are still part of the contract, so they are emitted at the end marked (unreferenced). If your $defs block is a shared library and most of it is irrelevant to this document, tick Skip unreferenced $defs.

Markdown table escaping

A pipe character ends a table cell and a newline ends the row, so a description containing either would silently break the table. Both are neutralised: pipes are backslash-escaped and newlines collapse to spaces. A multi-paragraph description therefore becomes one long line, which is the price of putting it in a table at all — if your descriptions are prose, generate the docs with the constraint columns off so there is room for them.

FAQ

Which drafts does it understand?

The keywords it reads are common to draft-07 and 2020-12, and it does not care which dialect $schema declares — $defs and definitions are both resolved. Draft-04's exclusiveMinimum: true boolean form is the one exception; it renders as a constraint but reads oddly. Run Migrate draft first if you have old schemas.

Why is a nested object a separate section instead of an indented table?

Because nesting depth in a schema is unbounded and Markdown tables do not nest. A section per object with links between them stays readable at any depth and survives being pasted into a docs site that reflows the content.

Can it go the other way — Markdown back to a schema?

No. Documentation loses information that a schema carries, so the round trip is not sound. Generate the schema from real data with the schema generator instead, then document it here.

Is anything uploaded?

No. The schema is parsed and rendered in your browser — nothing is sent anywhere.