How to convert json data to a github readme table
- Step 1Shape your options as a JSON array of objects — One option per object:
[{ "option": "port", "type": "number", "default": 8080, "description": "Listen port" }, ...]. The keys become the column headers in first-seen order, so order the keys the way you want the README columns. - Step 2Open the tool and drop the file — Drop a
.json,.ndjson,.jsonl, or.txtfile. An.xlsx/.xlsspreadsheet also works — the first sheet is read as rows and converted to JSON objects first. Everything parses in your browser. - Step 3Choose alignment — Pick Left (
:---), Center (:---:), or Right (---:). It applies to all columns uniformly. Left reads best for option/description tables; consider Right if you have a numeric default column and want it aligned. - Step 4Click Convert to Markdown — The tool writes a header row, an alignment-separator row, and one body row per option object. A single object (not an array) yields a one-row table.
- Step 5Check column order in the preview — The preview shows the raw Markdown (on-screen view truncates at 5,000 characters for very large tables, but Copy/Download still include the full text). Confirm the headers read in the order you intend — header order follows your object key order.
- Step 6Copy or download into README.md — Copy the Markdown or Download MD, then paste under your own
## Configurationheading. The tool gives you the table; you supply the heading and any intro sentence.
README table shapes the tool handles
Common README data and how the converter renders it. The tool always produces exactly one pipe table.
| README section | JSON shape to feed it | Result |
|---|---|---|
| Configuration / options reference | [{option, type, default, description}, ...] | One row per option, columns auto-detected |
| Supported values matrix | [{value, meaning, since}, ...] | One row per supported value |
| Dependency list | [{name, version, purpose}, ...] | One row per dependency |
| CLI flags | [{flag, alias, default, description}, ...] | One row per flag; alias blank where none |
package.json dependencies object | { "react": "^18", ... } (object, not array) | ONE row with a column per package — reshape to an array first |
Value rendering rules
How each JSON value type ends up in a Markdown cell. These come directly from the conversion logic.
| JSON value | Cell output | Example |
|---|---|---|
| String | Verbatim (pipes/newlines escaped) | "Listen port" → Listen port |
| Number / boolean | Stringified | 8080 → 8080, true → true |
| null / missing key | Empty cell | null → (blank) |
| Array or object | JSON.stringify inline | ["a","b"] → ["a","b"] |
Tier limits
Real numbers from the tier configuration. This is a Pro tool; free is gated by file size.
| Limit | Free | Pro |
|---|---|---|
| File size | 2 MB | 100 MB |
| Files per run | 1 | 10 (bulk) |
| Where it runs | Your browser | Your browser |
Cookbook
Real README data turned into Markdown tables, showing the exact output the converter emits.
Config options → README configuration table
ExampleThe everyday case for library authors: an options array becomes the ## Configuration table. Header order follows the first object's key order, so put option first.
Input (options.json):
[
{ "option": "port", "type": "number", "default": 8080, "description": "Listen port" },
{ "option": "verbose", "type": "boolean", "default": false, "description": "Verbose logging" }
]
Output (alignment: left):
| option | type | default | description |
| :--- | :--- | :--- | :--- |
| port | number | 8080 | Listen port |
| verbose | boolean | false | Verbose logging |Dependency list with a blank optional column
ExampleAdd a peer flag to only some dependencies. The column appears for all rows, blank where the key is absent — the union-of-keys behavior, ideal for marking peer deps without restructuring.
Input:
[
{ "name": "react", "version": "^18.0.0", "peer": true },
{ "name": "lodash", "version": "^4.17.0" }
]
Output:
| name | version | peer |
| :--- | :--- | :--- |
| react | ^18.0.0 | true |
| lodash | ^4.17.0 | |package.json dependencies object — reshape needed
ExampleA raw dependencies object has package names as keys, so converting it directly makes ONE wide row. Reshape into an array of {name, version} objects first (a tiny script or jq) to get a proper per-package table.
Wrong (object in):
{ "react": "^18.0.0", "lodash": "^4.17.0" }
→ | react | lodash |
| :--- | :--- |
| ^18.0.0 | ^4.17.0 | ← one row, not a list
Right (reshaped to array):
[{ "name": "react", "version": "^18.0.0" },
{ "name": "lodash", "version": "^4.17.0" }]
→ | name | version |
| :--- | :--- |
| react | ^18.0.0 |
| lodash | ^4.17.0 |Numeric defaults right-aligned
ExampleFor a flags table dominated by numeric defaults, right alignment makes the numbers line up. Alignment applies to all columns at once, so this is a whole-table choice.
Input:
[
{ "flag": "--retries", "default": 3 },
{ "flag": "--timeout", "default": 30000 }
]
Output (alignment: right):
| flag | default |
| ---: | ---: |
| --retries | 3 |
| --timeout | 30000 |Supported-values matrix from a manifest
ExampleA feature manifest listing supported values and the version each landed in becomes a clean reference table for the README.
Input:
[
{ "value": "auto", "meaning": "Detect from environment", "since": "1.2" },
{ "value": "always", "meaning": "Force on", "since": "1.0" }
]
Output:
| value | meaning | since |
| :--- | :--- | :--- |
| auto | Detect from environment | 1.2 |
| always | Force on | 1.0 |Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Feeding package.json directly
One-row tablepackage.json is one big object, and its dependencies/scripts are objects keyed by name. Converting it yields a single row with stringified nested values, not a dependency list. Extract and reshape the relevant object into an array of {name, version} first — a one-liner in jq or Node.
Config is a single nested object
Needs flatteningA config like { "server": { "port": 8080, "host": "0.0.0.0" } } becomes one row with a stringified server cell. Use json-flattener to turn it into dotted keys, then reshape into [{option, value}] rows for a readable table.
Invalid JSON in the file
Parse errorJSON.parse is strict — comments, trailing commas, and single quotes (all common in hand-edited config) throw. Repair with json-format-fixer or locate the exact error with json-validator, then convert.
A default value contains a pipe
PreservedA value like a regex default "^(a\|b)$" or a type string | number is backslash-escaped inside the cell so the column count stays correct. It renders with the visible pipe intact. This is automatic; there's no toggle in the UI.
Description with a newline
Collapsed to a spacePipe-table cells can't hold hard line breaks. A multi-line description has its newline replaced by a single space so the option stays on one row. Keep multi-paragraph notes out of the table and into prose below it.
Empty array
Header-onlyAn empty array has no keys, so no columns are produced — the output is an empty shell. Provide at least one object so the converter has keys to build headers from.
Inconsistent key casing across objects
Separate columnsOption and option are different keys, so they become two separate columns with half-blank rows. Normalize key casing before converting — json-key-renamer can rename keys to a single convention.
File over 2 MB on free
Blocked on freeFree caps input at 2 MB. README data rarely hits that, but a generated manifest with large inline examples can. Trim the array or upgrade to Pro (100 MB).
Frequently asked questions
Does this generate a whole README section?
No — it generates one Markdown table. There are no ### Option headings, bullet lists, or badges. You add the ## Configuration heading and intro yourself, then paste the table the tool produces.
Can I point it at package.json and get a dependency table?
Not directly. package.json's dependencies is an object keyed by package name, which becomes one wide row. Reshape it into an array of {name, version} objects first, then convert for a proper per-package table.
How are columns and their order decided?
Columns are the union of all keys across the objects, in the order keys first appear. There's no column picker. To control order, define all keys in your preferred order in the first object.
Can different columns have different alignment?
No. One alignment — Left, Center, or Right — applies to the whole table. The separator row uses :---, :---:, or ---: for every column.
How do booleans and numbers render?
As their string form: true, false, 8080. No quotes are added, so a default of 8080 shows as 8080 and false shows as false — exactly what you want in a config reference.
What happens to a nested object value?
It's JSON-stringified inline into the cell. Good for a short array like an enum; for a deeply nested object, flatten it first with json-flattener or document it in a code block beneath the table.
Why did two near-identical columns appear?
Your objects used inconsistent key names or casing (name vs Name). Each distinct key becomes its own column. Normalize keys first — json-key-renamer handles bulk renames.
Will the table render on the npm package page?
Yes. npm renders GitHub-flavored Markdown, including pipe tables, so the same output that looks right on GitHub renders on npmjs.com. No changes needed.
What file types can I drop?
.json, .ndjson, .jsonl, .txt, and .xlsx/.xls. A spreadsheet's first sheet is read into a JSON array of objects before the table is built — useful if your options live in a sheet.
Is my config uploaded?
No. Everything runs in your browser. The config file — including any private defaults or tokens — is never sent to JAD Apps. Only an anonymous run count is logged if you're signed in.
How large can the input be?
2 MB on free, 100 MB on Pro. README data is small, so free is normally plenty.
Can I regenerate the table automatically on each release?
Yes — it's a Pro tool with API access. Run it via the local runner in your release script to rebuild the README table from your config file. Conversion runs locally, so the file never leaves your machine.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.