Developer FIELD NOTES · 4 MIN READ
Markdown Tables: Syntax and How to Generate Them from Data
How Markdown table syntax works — header, separator, pipes — and how to turn CSV, tab, or space-separated data into a valid table.
A Markdown table is a fence made of punctuation: a row of cells wrapped in pipes, a line of dashes holding it up, and strict rules about who sits where. The syntax is easy to read and miserable to type — count the pipes wrong once and the whole table silently becomes a paragraph. That gap between "looks simple" and "is finicky" is exactly why generating tables from data you already have beats hand-building them.
The three parts of every table
A valid table needs exactly three things: a header row, a separator row, and the body rows. The separator is the part people underestimate — a line of at least three dashes per column, joined by pipes, is what tells the renderer "the lines above and below are table rows, not text". Take real data:
name,age,city
Alice,34,Portland
Bob,29,Austin
and the generated table is:
| name | age | city |
| --- | --- | --- |
| Alice | 34 | Portland |
| Bob | 29 | Austin |
Every cell gets its own padding spaces, and the separator uses one --- per column. Alignment variants exist — :--- for left, :--: for center, ---: for right — but the plain form renders left-aligned everywhere, which is the safe default when the goal is "table that works".
Choosing the delimiter
The generator splits your input before it builds anything, and the delimiter decides how. Comma is the default and matches what spreadsheets copy out. Tab matches what you get from pasting directly out of Excel or Google Sheets — a mode that saves you from a spreadsheet full of almost-invisible tab characters. Pipe and whitespace round it out; whitespace mode splits on any run of spaces or tabs, handy for column-aligned plain text. Cells are trimmed as they are split, so stray spaces around commas disappear into the padding the generator adds anyway. For the wider picture of where CSV comes from and why it is trickier than it looks, see How CSV Files Work.
The messy cases: ragged rows and hostile cells
Real data is not rectangular. If one row has fewer cells than the widest row, the missing cells are padded with empty strings so every output row has the same column count — a table renderer needs that symmetry. Two hazards come from the inside: a cell containing a pipe would break the table it lives in, so pipes in cell content are escaped as \|; and a literal newline inside a cell is flattened to a space, because a raw line break would end the row. Neither is magic — they are the minimum transformations that keep the output parseable as a table.
No header? Borrow one
Markdown tables require the separator row, and the separator only means "column boundary" when there is a header above it — so a table without a header is not a thing you can skip to. When you say the first row is data rather than labels, the generator invents placeholder headers Column 1, Column 2, … and shifts your real rows into the body. Feed it a\tb and 1\t2 as tab-delimited data with no header, and you get | Column 1 | Column 2 | on top and both of your rows below, intact. Rename the placeholders to real labels and the table is done.
Tables are the newest part of Markdown
Worth knowing: tables are not in the original Markdown grammar. They arrived as an extension (popularized by PHP Markdown Extra and GitHub Flavored Markdown) and are now near-universally supported, but strict CommonMark treats those pipe rows as plain text. That is why a table pasted into a renderer without table support looks like a wall of pipes. The full context of blocks, inline styles, and flavors is in Markdown Explained.
Try it yourself
Copy two rows out of a spreadsheet, paste them into the Markdown Table Generator, and switch the delimiter to tab — the table should build itself. Already have a Markdown table that is misaligned or missing its separator? The Markdown Table Formatter repairs existing tables rather than building new ones. And if the data you are tabling lives in JSON, the CSV to JSON Converter moves it between the two formats first.