JSON to Markdown: Convert JSON Data to Tables, Lists, and Documents
Last updated:
Converting JSON to Markdown is useful for generating documentation from API responses, creating changelogs from structured data, building README tables from config, and producing reports from analytics JSON. This guide covers table generation, nested list output, code blocks, and full document generation.
JSON Array to Markdown Table (JavaScript)
A Markdown pipe table has a header row, a separator row (with ---), and data rows — all using | to delimit cells.
// Input
const users = [
{ id: 1, name: 'Ada Lovelace', role: 'engineer', active: true },
{ id: 2, name: 'Alan Turing', role: 'researcher', active: true },
{ id: 3, name: 'Grace Hopper', role: 'engineer', active: false },
]
function escapeCell(val) {
return String(val ?? '').replace(/\|/g, '\\|').replace(/\n/g, ' ')
}
function jsonToMarkdownTable(data) {
if (!Array.isArray(data) || data.length === 0) return ''
const headers = Object.keys(data[0])
const headerRow = '| ' + headers.map(escapeCell).join(' | ') + ' |'
const separator = '| ' + headers.map(() => '---').join(' | ') + ' |'
const rows = data.map(row =>
'| ' + headers.map(h => escapeCell(row[h])).join(' | ') + ' |'
)
return [headerRow, separator, ...rows].join('\n')
}
console.log(jsonToMarkdownTable(users))Output:
| id | name | role | active |
| --- | --- | --- | --- |
| 1 | Ada Lovelace | engineer | true |
| 2 | Alan Turing | researcher | true |
| 3 | Grace Hopper | engineer | false |JSON to Markdown Table (Python)
import json
from tabulate import tabulate # pip install tabulate
with open('users.json') as f:
data = json.load(f)
# Markdown pipe table — renders on GitHub, GitLab, Obsidian
print(tabulate(data, headers='keys', tablefmt='pipe'))
# Output:
# | id | name | role | active |
# |-----:|:-------------|:-----------|:---------|
# | 1 | Ada Lovelace | engineer | True |
# | 2 | Alan Turing | researcher | True |
# | 3 | Grace Hopper | engineer | False |Without tabulate, build the table manually:
def json_to_md_table(data):
if not data:
return ''
headers = list(data[0].keys())
rows = [headers] + [[str(row.get(h, '')) for h in headers] for row in data]
sep = ['---'] * len(headers)
rows.insert(1, sep)
return '\n'.join('| ' + ' | '.join(r) + ' |' for r in rows)
print(json_to_md_table(data))JSON to Markdown Code Block
// Wrap JSON in a fenced code block with json syntax highlighting
const FENCE = '```'
function jsonToCodeBlock(data, indent = 2) {
return FENCE + 'json\n' + JSON.stringify(data, null, indent) + '\n' + FENCE
}
const response = { id: 'usr_123', email: 'ada@example.com', plan: 'pro' }
console.log(jsonToCodeBlock(response))
// Output renders as:
// (fence)json
// {
// "id": "usr_123",
// "email": "ada@example.com",
// "plan": "pro"
// }
// (fence)Nested JSON to Markdown List
function jsonToMarkdownList(data, depth = 0) {
const indent = ' '.repeat(depth)
if (Array.isArray(data)) {
return data.map(item => {
if (typeof item === 'object' && item !== null) {
return indent + '-\n' + jsonToMarkdownList(item, depth + 1)
}
return indent + '- ' + String(item)
}).join('\n')
}
if (typeof data === 'object' && data !== null) {
return Object.entries(data).map(([key, val]) => {
if (typeof val === 'object' && val !== null) {
return indent + '- **' + key + '**:\n' + jsonToMarkdownList(val, depth + 1)
}
return indent + '- **' + key + '**: ' + String(val)
}).join('\n')
}
return indent + '- ' + String(data)
}
const config = {
server: { host: 'localhost', port: 3000 },
features: ['auth', 'api', 'webhooks'],
debug: false,
}
console.log(jsonToMarkdownList(config))Output:
- **server**:
- **host**: localhost
- **port**: 3000
- **features**:
- auth
- api
- webhooks
- **debug**: falseUsing json2md (npm)
// npm install json2md
import json2md from 'json2md'
const doc = json2md([
{ h1: 'API Reference' },
{ p: 'This document describes the Users API.' },
{ h2: 'GET /users' },
{ p: 'Returns a paginated list of users.' },
{ h3: 'Response Fields' },
{
table: {
headers: ['Field', 'Type', 'Description'],
rows: [
['id', 'string', 'Unique user identifier'],
['email', 'string', 'User email address'],
['createdAt', 'string', 'ISO 8601 creation timestamp'],
],
},
},
{ h3: 'Example Response' },
{
code: {
language: 'json',
content: JSON.stringify({
data: [{ id: 'usr_123', email: 'ada@example.com', createdAt: '2024-01-15T09:00:00Z' }],
pagination: { hasMore: false, count: 1 },
}, null, 2),
},
},
])
console.log(doc)Generating README Tables from package.json
import { readFileSync } from 'fs'
const pkg = JSON.parse(readFileSync('package.json', 'utf-8'))
// Generate a dependencies table for README
function depsToTable(deps = {}) {
const rows = Object.entries(deps).map(([name, version]) => ({
Package: name,
Version: version,
Link: 'https://npmjs.com/package/' + name,
}))
return jsonToMarkdownTable(rows)
}
const readme = [
'## Dependencies',
'',
depsToTable(pkg.dependencies),
'',
'## Dev Dependencies',
'',
depsToTable(pkg.devDependencies),
].join('\n')
console.log(readme)Special Characters in Markdown Tables
| Character | Issue | Fix |
|---|---|---|
| | Breaks column separator | Replace with \| |
| newline | Ends table row | Replace with space or <br> |
| leading/trailing spaces | Ignored in GFM tables | Trim values |
` | Starts inline code span | Wrap in more backticks or escape as \` |
* or _ | Bold/italic markup | Escape as \* or \_ |
FAQ
How do I convert a JSON array to a Markdown table in JavaScript?
Extract headers from the first object's keys, build the header row as | key1 | key2 |, add a separator row | --- | --- |, then map each object to a data row. Escape pipe characters in values (.replace(/\|/g, '\\|')) and replace newlines with spaces. This produces a GFM pipe table that renders on GitHub, GitLab, Notion, and most Markdown renderers.
How do I convert a nested JSON object to a Markdown document?
A recursive function maps nesting level to heading depth (depth 1 → ##, depth 2 → ###), objects to heading + child content, arrays to unordered lists, and primitive values to **key**: value pairs. The json2md npm package offers a declarative descriptor API: pass an array specifying whether each section should be an h1, p, table, ul, or code block. This gives you precise control over the output structure.
What npm packages convert JSON to Markdown?
json2md — descriptor-based, supports headings, paragraphs, tables, lists, code blocks. markdown-table (micromark ecosystem) — lightweight, 2D array to GFM table. jsonmd — automatic tree-to-Markdown conversion. For tables specifically, the table module in unified produces well-formatted output. All are installable with npm install or pnpm add.
How do I generate API documentation from a JSON response?
The standard workflow: use quicktype or json-schema-inference to infer a JSON Schema from a sample response, then use a template engine (Handlebars, Nunjucks) to render a Markdown template with the schema data. The template includes an overview table (field name, type, required, description) and a code block with the sample. For OpenAPI specs, widdershins converts openapi.yaml or swagger.json to Markdown documentation automatically. RedocPublishing generates a static HTML documentation site from an OpenAPI spec.
How do I convert JSON to Markdown in Python?
For tables, tabulate(data, headers='keys', tablefmt='pipe') is the shortest path. Install with pip install tabulate. For full documents, mdutils provides a builder API. For manual implementation, use Python's f-strings or string joining to build the table, being careful to escape | characters in cell values. The json module handles parsing; the table generation is pure string manipulation.
How do I handle special characters in JSON values when converting to Markdown?
The most important escaping: pipe characters (|) must become \| to avoid breaking table column separators. Newlines must become a space or <br>. Backticks that would start code spans should be escaped. Define an escape function applied to every cell value before joining with | separators: (v) => String(v ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ").
Can I convert JSON to a Markdown code block?
Yes: wrap JSON.stringify(data, null, 2) in a fenced code block with the json language identifier: ```json\n...\n```. This enables syntax highlighting in GitHub, VS Code previews, GitLab, and Obsidian. It's the most common pattern for including example API payloads in documentation, README files, and CHANGELOG entries.
How do I convert JSON to a Markdown list (nested bullets)?
A recursive function handles the three cases: primitive values become bullet items, arrays recurse over each element, and objects recurse over each key-value pair with the key bolded. Use 2-space indentation per depth level to create nested bullets. GFM (GitHub Flavored Markdown) supports unlimited nesting depth. Arrays of strings or numbers produce simple bullet lists; nested objects produce indented sublists.
Further reading and primary sources
- json2md on npm — Convert structured JSON descriptors to Markdown: headings, paragraphs, tables, lists, code
- tabulate (Python) — Generate Markdown tables from Python dicts/lists with tablefmt="pipe"
- GitHub Flavored Markdown Tables — Official GFM pipe table syntax reference
- JSON to HTML Table (Jsonic) — Convert JSON arrays to HTML tables in JavaScript and Python with auto headers
- JSON Examples (Jsonic) — Real-world JSON data structures: users, products, APIs, configuration files