JSON to Markdown Table

Paste a JSON array and get a Markdown table for the docs, the PR description or the incident write-up. Every key that appears in any object becomes a column, so a record that lacks a field shows an empty cell in that column instead of shifting its other values one column to the left. Set Align to left, center, right or numbers right to add the colons renderers use for column alignment.

JSON Input

1 JSON to Markdown Table example

Input JSON

[
    { "id": 1, "name": "Ada Lovelace", "role": "admin", "tags": ["math", "engines"] },
    { "id": 2, "name": "Grace Hopper", "role": "editor", "tags": ["cobol"] },
    { "id": 3, "name": "Linus", "role": null, "active": false }
]

Markdown output

| id  | name         | role   | tags               | active |
| --- | ------------ | ------ | ------------------ | ------ |
| 1   | Ada Lovelace | admin  | ["math","engines"] |        |
| 2   | Grace Hopper | editor | ["cobol"]          |        |
| 3   | Linus        |        |                    | false  |

The third object has no tags and adds an active key, so the table has both columns and the gaps show as empty cells. A null value also renders as an empty cell.

2 How values are written

Column order

Keys appear in the order they are first seen: all of the first object's keys, then any new ones from later objects, appended on the right.

Nested objects and arrays

The tool writes them into the cell as compact JSON, such as ["math","engines"]. They are not flattened into dotted columns, so the column count stays the same as the number of top-level keys.

Pipes and line breaks

A | in a string is escaped as \| and a newline becomes <br>, because a row has to stay on one line.

Other shapes

A single object becomes a one-row table. An array of plain values (strings, numbers) becomes one column called value.

3 When the table gets too wide

Trim the objects to the fields your reader needs before you convert. Markdown tables do not wrap well: once the columns outgrow the page, GitHub adds a horizontal scrollbar, and each raw row becomes a line too long to review. Cut the fields down with jq 'map({id, name, role})', or with the JSONPath tester if you only want part of a larger response.

How to use the JSON to Markdown Table tool

  1. Paste a JSON array of objects into the JSON Input pane, or click Upload JSON. Dummy Data loads a small sample with a missing key and a nested array.
  2. If the header shows Invalid JSON with a line and column, fix the input there first. A single object is accepted and becomes a one-row table.
  3. Choose an alignment from the Align dropdown and keep or untick Pad columns.
  4. Switch to Preview to see the rendered table, then click Copy Markdown. Clear empties both panes.

How to convert JSON to a Markdown table in JavaScript, Python and PHP

JavaScript / Node.js

const data = [
  { id: 1, name: "Ada", tags: ["math"] },
  { id: 2, name: "Grace | Hopper", active: true },
];

// Union of keys, in the order they first appear
const keys = [...new Set(data.flatMap((o) => Object.keys(o)))];

const show = (v) =>
  v === undefined || v === null ? "" : typeof v === "object" ? JSON.stringify(v) : String(v);
const cell = (v) => show(v).replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
const line = (cells) => `| ${cells.join(" | ")} |`;

const md = [
  line(keys.map(cell)),
  line(keys.map(() => "---")),
  ...data.map((o) => line(keys.map((k) => cell(o[k])))),
].join("\n");
console.log(md);

Python

import json

data = json.loads('[{"id": 1, "name": "Ada", "tags": ["math"]},'
                  ' {"id": 2, "name": "Grace | Hopper", "active": true}]')

# dict.fromkeys keeps first-seen order and drops duplicates
keys = list(dict.fromkeys(k for row in data for k in row))

def cell(v):
    if v is None:
        s = ""
    elif isinstance(v, (dict, list)):
        s = json.dumps(v, separators=(",", ":"))
    elif isinstance(v, bool):
        s = "true" if v else "false"
    else:
        s = str(v)
    return s.replace("\\", "\\\\").replace("|", "\\|").replace("\n", "<br>")

def line(cells):
    return "| " + " | ".join(cells) + " |"

out = [line(cell(k) for k in keys), line("---" for _ in keys)]
out += [line(cell(row.get(k)) for k in keys) for row in data]
print("\n".join(out))

The bool check matters: str(True) gives True, not the JSON spelling true.

PHP

<?php
$json = '[{"id": 1, "name": "Ada", "tags": ["math"]},
          {"id": 2, "name": "Grace | Hopper", "active": true}]';
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

$keys = [];
foreach ($data as $row) {
    foreach (array_keys($row) as $k) $keys[$k] = true;
}
$keys = array_keys($keys);

$cell = function ($v): string {
    if ($v === null) $s = '';
    elseif (is_array($v)) $s = json_encode($v, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    elseif (is_bool($v)) $s = $v ? 'true' : 'false';
    else $s = (string) $v;
    return str_replace(["\\", '|', "\r\n", "\n"], ["\\\\", '\|', '<br>', '<br>'], $s);
};
$line = fn(array $cells) => '| ' . implode(' | ', $cells) . ' |';

$out = [$line(array_map($cell, $keys)), $line(array_fill(0, count($keys), '---'))];
foreach ($data as $row) {
    $out[] = $line(array_map(fn($k) => $cell($row[$k] ?? null), $keys));
}
echo implode("\n", $out), "\n";

Decoding with true as the second argument gives associative arrays, so nested objects and lists both go through json_encode.

Common errors and how to fix them

Invalid JSON on line N (trailing comma)
JSON does not allow a comma after the last item in an array or object. Remove it. JavaScript object literals allow the comma, which is why it slips in.
Expected a JSON array or object
The input is a bare string or number. Wrap the records in [ ] so there is something to make rows from.
Only one row appears for an API response
The records are probably nested, as in {"data": [...]}. Paste only the inner array, or pull it out with jq '.data' first.
Cells contain [object Object] in your own code
String() on an object gives [object Object]. Use JSON.stringify for objects and arrays, as the snippets above do.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

How do I turn a JSON array into a Markdown table?

Paste the array into the JSON Input pane and the table appears on the right. Each object becomes a row and each key becomes a column; click Copy Markdown to take it.

What if objects have different keys?

Every key found in any object becomes a column, in the order it was first seen. Objects that lack a key get an empty cell in that column.

How are nested objects and arrays shown?

The tool writes them into the cell as compact JSON, for example ["a","b"] or {"x":1}. They are not flattened into separate columns, so the table has one column per top-level key.

What happens to null values?

null and missing keys both render as an empty cell. true and false are written as text.

Why does it say Invalid JSON on a line?

The input failed to parse, and the line and column point to where the parser gave up. Trailing commas, single quotes and unquoted keys are the usual causes, since JSON allows none of them.

How do I center or right-align a Markdown table column?

Set Align. Left, center and right put colons in the separator row of every column, so :---: centers and ---: right-aligns, which GitHub, GitLab and most other renderers honor. Align: none writes plain dashes and leaves the choice to the renderer, which usually means left. The Preview tab shows cell content only, so check alignment in the Markdown itself or after pasting.

Can numbers be right-aligned automatically?

Choose Align: numbers right. The tool checks each column, and when every non-empty cell is a number, including forms like 1,200, -3.5 and 12%, that column gets ---: so the digits line up on the right. Text columns keep plain dashes. A column with a single non-numeric value such as n/a stays unaligned, so clean those cells first.

What does Pad columns do?

With it on, cells are padded with spaces so the pipes line up and the raw Markdown reads as a table in a code review or a plain text editor. The rendered table is identical either way. Untick it for a compact table in a file that is diffed often, since padding means one longer value changes the width of every row in that column.

Related

JSON to Table shows the same data as an HTML table you can copy into an email. For CSV input use CSV to Markdown Table, and to check the JSON itself first, run it through the JSON formatter.

More Data Converters

Browse all data converters

Copied to clipboard!