How to document data files as markdown tables
- Step 1Assemble the documentation CSV — Use a CSV whose columns map to your doc table: for a data dictionary, columns like
Column,Type,Required,Description. For sample records, the raw data extract itself. - Step 2
- Step 3Keep First row is header on — For a dictionary the first row holds the column names — leave the option checked. For a values-only lookup with no header, uncheck it.
- Step 4Convert and review — Run the tool. Confirm that descriptions containing commas, pipes, or parentheses survived intact and that the column count matches your CSV header.
- Step 5Add alignment by hand if needed — The separator is plain
---(no alignment). If a numeric or boolean column reads better right-aligned, edit the separator line to use--:after conversion. - Step 6Commit into the docs — Copy the Markdown into the relevant
.mdpage (or download<name>-table.md) and commit it alongside the rest of your docs-as-code source.
Documentation table patterns
Common docs tables and the CSV shape that produces them. The first row supplies the headers in each case.
| Doc table | CSV columns | Why a table beats prose |
|---|---|---|
| Data dictionary | Column, Type, Required, Description | Reviewers scan a grid faster than paragraphs; columns line up so omissions are obvious. |
| Enum / allowed-values reference | Value, Meaning, Since | A two- or three-column table is the clearest way to list a closed set of codes. |
| Sample records | the raw data extract | Shows real shapes (date formats, null handling) without shipping a downloadable file. |
| Field-mapping (source → target) | Source, Target, Transform | Side-by-side mapping is unreadable as prose; a table makes the correspondence explicit. |
How docs-specific content is handled
The sanitising rules that matter most for prose-heavy documentation cells.
| Content in a cell | Handling | Result in table |
|---|---|---|
Union type string | null | | escaped to \| | Renders as the literal text string | null, not two columns. |
| Multi-sentence description (quoted) | Kept as one cell | Full text in a single cell, commas and all. |
| Description with an embedded newline | Newline folded to a space | One continuous line; no broken row. |
| Code sample with backticks | Passed through verbatim | Backticks are not special to the parser; they render as inline code in the table cell. |
| Empty / NULL cell | Rendered as empty | Shows a blank cell; pre-fill NULL in the CSV if you want it visible. |
Cookbook
Data-dictionary and sample-record CSVs converted to the Markdown tables you commit into docs.
A data dictionary
Column-name / type / description rows become a dictionary table. Note the union type with a pipe in the last row.
Input (CSV): Column,Type,Required,Description user_id,integer,yes,Primary key email,string,yes,Login address locale,string | null,no,IETF tag or null Output (Markdown): | Column | Type | Required | Description | | --- | --- | --- | --- | | user_id | integer | yes | Primary key | | email | string | yes | Login address | | locale | string \| null | no | IETF tag or null |
An enum reference
A closed set of status codes documented as a table. The first row supplies the headers.
Input (CSV): Value,Meaning,Since active,Account in good standing,1.0 suspended,Temporarily disabled,1.2 deleted,Soft-deleted record,2.0 Output (Markdown): | Value | Meaning | Since | | --- | --- | --- | | active | Account in good standing | 1.0 | | suspended | Temporarily disabled | 1.2 | | deleted | Soft-deleted record | 2.0 |
Sample records with a comma inside a field
A sample extract where an address contains a comma. The quoted field stays one cell.
Input (CSV): id,name,city 1,"Acme, Inc.",Berlin 2,Globex,Tokyo Output (Markdown): | id | name | city | | --- | --- | --- | | 1 | Acme, Inc. | Berlin | | 2 | Globex | Tokyo |
Multi-sentence description folded to one line
A two-sentence description with a line break inside the quoted cell becomes a single spaced line.
Input (CSV): Column,Description retries,"Number of attempts. Resets nightly." Output (Markdown): | Column | Description | | --- | --- | | retries | Number of attempts. Resets nightly. |
Headerless lookup table
A code-to-label lookup with no header row. Uncheck First row is header and label columns are generated.
Input (CSV), First row is header = OFF: US,United States DE,Germany JP,Japan Output (Markdown): | Col 1 | Col 2 | | --- | --- | | US | United States | | DE | Germany | | JP | Japan |
Edge cases and what actually happens
Empty CSV after trimming
No data: invalid inputAn empty file, or one that is only blank lines, yields the literal output No data found. rather than an empty dictionary table. Paste real rows and re-run.
Union types with pipe characters
EscapedType descriptions like string | null or enum a|b|c have each | escaped to \|, so the description renders as text instead of splitting into extra columns.
NULL / empty cells in sample data
Rendered emptyAn empty CSV cell becomes an empty table cell — easy to misread as a missing column. If a blank is meaningful in your docs, write NULL or — into the CSV before converting.
Real PII in a sample-records extract
Anonymise firstFor public-facing docs, anonymise production data before converting. Processing is browser-only so nothing is uploaded, but the resulting Markdown is committed to a repo — scrub names, emails, and IDs first.
Description containing a literal backtick block
Passed throughBackticks are not special to the CSV parser, so an inline code sample in a description renders as inline code in the cell. A fenced multi-line code block, however, will lose its line breaks (folded to spaces) — keep code samples to one line in a table cell.
Duplicate header names
PreservedIf a dictionary CSV accidentally has two Description columns, both are emitted verbatim. Rename one in the source to keep the table unambiguous for strict renderers.
Need column alignment in the dictionary
ManualThe separator is always ---. Add --: to the separator line by hand if you want a Required or numeric column right-aligned — the tool does not produce alignment markers.
Very wide dictionary (many attribute columns)
SupportedThere is no column cap, but a dictionary with 10+ columns is hard to read in rendered docs. Split into a core table plus a supplementary attributes table.
Schema export larger than the free tier
Tier limitA big schema or sample extract can exceed Free's 1 MB / 500,000-character cap. Pro raises it to 10 MB / 5,000,000 characters. The character count, not just file size, is what trips on prose-heavy CSVs.
Frequently asked questions
Should I anonymise the data first?
Yes for anything destined for public docs. Conversion is browser-only so nothing uploads, but the Markdown gets committed to a repo — scrub names, emails, and IDs from sample records before converting.
How wide can the table get?
There is no column limit, but very wide tables become unreadable in rendered docs. For a data dictionary with many attributes, split into a core table and a supplementary one.
Will it handle date columns?
Dates render exactly as the CSV string. The converter does not reformat them, so pre-format dates in the source for consistent display across the doc.
Do union types like `string | null` break the table?
No. Each | is escaped to \|, so a type description like string | null renders as literal text rather than creating extra columns.
What happens to a multi-sentence description with a line break?
The line break is folded to a single space, because a Markdown pipe-table cell cannot contain a real newline. The full text stays in one cell on one line.
Can I put a code sample in a description cell?
Inline code in backticks renders fine. A multi-line fenced block, though, loses its line breaks (they fold to spaces) — keep code in a table cell to a single line.
How do I show NULL values in sample records?
Empty CSV cells render as empty table cells. If you want NULLs visible, write NULL or a dash into the CSV before converting; the tool does not infer them.
Does it auto-detect the header row?
The first row is treated as the header by default (hasHeader is on). For a values-only lookup table with no header, uncheck First row is header and the tool generates Col 1, Col 2 … labels.
Can I set alignment for the Required / boolean column?
Not from the tool — the separator row is always ---. Edit the separator line to --: after conversion if you want a column right-aligned.
Is the CSV uploaded anywhere?
No. PapaParse runs entirely in your browser, so a CSV containing production or sample-PII data never reaches a server.
How big a CSV can I document?
Free allows 1 MB and 500,000 characters in one file; Pro 10 MB / 5,000,000; Pro-media 50 MB / 20,000,000; Developer 500 MB with no character cap. Prose-heavy CSVs hit the character limit before the byte limit.
My schema is in JSON, not CSV — is there a tool for that?
Yes. JSON to Markdown Table converts an array of JSON objects. To generate a heading-based contents list for a long docs page, use Markdown Table of Contents.
Privacy first
All Markdown processing runs locally in your browser using JavaScript. No file is ever uploaded to JAD Apps servers — only metadata counters are saved for signed-in dashboard stats.