Saltar al contenido principal

JSON to Markdown Table

This converter renders a JSON array of objects as a GitHub-flavoured Markdown table in your browser. Columns are the first-seen union of every object's keys, pipes are escaped as \|, newlines become <br>, and the separator row matches your header — so the output pastes straight into any Markdown renderer.

Solo local

La interfaz de esta herramienta está en inglés.

La guía de abajo solo está disponible en inglés.

JSON to Markdown Table explained

Documentation runs on Markdown tables — README feature lists, changelog entries, comparison sections in a pull request — and the data behind them usually starts as JSON: an API response, a test report, an export. Typing the table by hand is where the errors creep in, because Markdown tables have rules that are easy to half-know: one row per line, cells split on pipes, and a separator row that decides whether the columns exist at all.

This converter does the typing for you, by GitHub-flavoured Markdown's rules. The header row is the ordered union of every object's keys, in first-seen order, so a key that appears from the second record onward still gets its column. A pipe inside a value is escaped as \| so it cannot split a cell, a newline inside a value becomes <br> so it cannot split a row, and objects or arrays nested inside a record are rendered as compact JSON text so nothing vanishes.

As everywhere on this site, the conversion happens entirely in your browser. The JSON is parsed with the browser's own JSON.parse, the Markdown is built in the tab, and nothing is sent anywhere — DevTools' Network panel stays silent through every conversion, and the page's Content-Security-Policy blocks outbound requests regardless.

The crossing is useful in both directions — a table maintained in a wiki can become data again — and the Markdown to JSON converter page parses GitHub table syntax back into records.

If the destination is a spreadsheet rather than documentation, the JSON to CSV converter produces RFC 4180 rows from the same records.

How the conversion actually works

The engine parses your JSON with JSON.parse and requires the top level to be an array of objects — the only shape that means rows. It then walks the records once, collecting keys into an ordered union: the first record's keys open the table, and a key first seen in a later record is appended to the right rather than displacing the column order you already have. Records that lack a key simply leave that cell empty. Nothing about the result depends on tooling you do not have: the table is plain text, so it survives copy-paste, code review and static-site builds alike. Then the table is written, one rule per hazard:

  • Header: one row of the union's keys, then a separator row of three dashes per column — the line that makes the block a table in every GitHub-flavoured renderer.
  • Pipes: a | inside a value is emitted as \|, the escape GFM defines, so a value like a|b stays a single cell.
  • Newlines: a \n inside a value becomes <br>, because a real newline would end the row and corrupt everything beneath it.
  • Nested values: an object or array inside a record is rendered as compact JSON text in its cell, so nested data is visible rather than silently dropped.

What the output looks like

The worked example below is the exact pair the converter's Load sample button produces: two people, where the first record's notes value contains a pipe and the second's contains a newline. The escaped pipe renders as a literal | inside its cell, the newline renders as a line break under <br>, and both rows keep their three columns. Rows are wrapped in leading and trailing pipes, which is the form every renderer and diff tool reads most reliably.

Paste the output into any GitHub-flavoured renderer and the preview you see there is what readers get. The table is also stable under diff for a quiet reason: column order depends on document order rather than a sort, so a record that gains a key appends a column instead of reshuffling the ones your readers already know.

The cell rules at a glance

Each hazard a table cell can contain, and its emitted form:

Cell contentEmitted asWhy
a|ba\|bA raw pipe would split the cell
line one\nline twoline one<br>line twoA raw newline would end the row
{"x": 1}Compact JSON textNested values shown, not dropped
truetrueBooleans render bare
(missing key)(empty cell)Ragged records stay aligned

Inputs this converter refuses

Two shapes have no faithful table and are refused with a specific message rather than coerced:

  • A top level that is not an array — a single object is one row with no table to join, and wrapping it in a synthetic array would invent structure you did not write.
  • An array whose elements are not all objects — a list of scalars has no keys, so there is nothing to become column headers; the converter names the offending index.

Frequently asked questions

Is any data sent to a server when I convert JSON to Markdown?

No. Parsing and rendering both run in this browser tab with page-local JavaScript. There is no upload endpoint, and the Content-Security-Policy forbids outbound connections. You can confirm both in DevTools: open the Network panel, convert a document, and observe that no request is made at any point.

Which Markdown dialect is the output written for?

GitHub-flavoured Markdown, the table syntax used by GitHub, GitLab and most documentation tools. The signature is the separator row of dashes beneath the header — this converter emits three dashes per column without alignment colons, so cells default to left alignment — and rows carry leading and trailing pipes for maximum renderer compatibility.

Why does a pipe inside my value need escaping?

Because the pipe is the cell delimiter: a raw | would be read as the end of one cell and the start of another, silently shifting every cell after it. GFM's escape is the backslash-pipe pair \|, which renders as a literal pipe inside the cell. The converter applies it to every value, so a code sample like a|b arrives in the table looking the way it started.

Why do newlines in values become <br> and not real line breaks?

A Markdown table row is a single line by definition — a raw newline inside a cell ends the row, and the renderer treats the remainder as a new paragraph, corrupting the table. The HTML <br> tag renders as a line break inside the cell, which is the convention GitHub itself documents for multi-line cell content.

How is the column order decided?

By the union of every record's keys in first-seen order: the first record's keys set the initial columns, and any key appearing later is appended to the right. Records missing a key leave that cell empty. The order is stable — document order, not alphabetical — because a converter that re-sorted your columns would make every later diff of the output noisy.

What happens to nested objects and arrays in a record?

They are rendered as compact JSON text inside their cell, so the information stays visible instead of being dropped or flattened out of recognition. If the nested structure matters downstream — filtering, sorting, charting — flatten it first with the JSON to CSV converter, which turns nested paths into columns; for reading and review, the JSON-text cell is usually exactly enough.