A Markdown table is three kinds of rows, and each one is built from pipe characters. First comes a header row like | Name | Age |. Under it sits a divider row of hyphens, | --- | --- |. Every line after that is one row of data.
Colons in the divider row set the alignment. Write :--- for left, :---: for center and ---: for right. Nothing else is needed - No plugin, no HTML, no drawing tool.
Tables come from GitHub Flavored Markdown rather than the original 2004 syntax. They render on GitHub, GitLab, Reddit, Obsidian, VS Code and in our editor. A few chat apps still print your raw pipes as plain text, and the support table below names them.
At a glance
| Required rows | A header row plus a divider row of hyphens |
|---|---|
| Alignment control | Colons in the divider row: :--- , :---: , ---: |
| Inside a cell | Inline formatting only, no lists or paragraphs |
| Dialect needed | GitHub Flavored Markdown, not original Markdown |
| Escaping a pipe | Put a backslash in front of it |
Build a table in three rows
- Every table needs a header row and a divider row of hyphens before any data.
- Colons in the divider row set alignment, and the hyphen count between them changes nothing.
- A cell holds inline formatting only, so a list or a blank line ends the table early.
- Tables are a GFM feature, which is why Discord shows your pipes instead of a grid.
Paste this into the editor and watch the preview pane.
| Plan | Price | Storage |
| -------- | ------- | ------- |
| Free | $0 | 5 GB |
| Pro | $9/mo | 100 GB |
| Team | $29/mo | 1 TB |
The result is a three-column table with a bold header and three data rows. The first line becomes the header cells. The hyphen line then vanishes, because its only job is to tell the parser that this block is a table. Every line after it becomes one row.
The tidy padding above is cosmetic. |Plan|Price|Storage| renders exactly the same. Spaces only keep the source readable for whoever edits the file next.
Set column alignment with colons
Alignment lives in the divider row, one setting per column.
| Item | Qty | Unit price |
| :--------- | :-: | ---------: |
| Notebook | 3 | $4.50 |
| Pen | 12 | $1.20 |
What each colon pattern does
:---aligns the column left. You get the same result when the divider row has no colons at all.:---:aligns it center, which suits short labels and single digits.---:aligns it right, so the decimal points in a price column line up.
Whatever you choose applies to the header cell as well as the body cells under it.
What the hyphens do not control
The number of hyphens between the colons changes nothing. :-: and :-------: give the same centered column. Width is decided by the renderer and by the content, never by your source file.
Watch out: the divider row needs one entry per header column, in the same order. Miscount by one and the block stops being a table. Every row then falls back to a plain paragraph of pipes.
What fits inside a cell
Cells take inline formatting and nothing else. All of these work.
| Field | Example |
| ------ | -------------------------------- |
| Bold | **shipped** |
| Italic | *draft* |
| Code | `npm install` |
| Link | [docs](https://example.com/docs) |
| Image |  |
| Break | line one<br>line two |
What never works in a cell
Anything that needs a second line is out. Lists, paragraphs, blockquotes and fenced code blocks all end the row, because the parser stops reading at the newline. For a line break inside a cell, use the HTML tag <br>. GitHub, GitLab and most other renderers accept it.
Empty cells and stray pipes
An empty cell is legal. Write | | and it renders blank, which is the honest way to show that there is no data. A literal pipe is the opposite problem. Escape it with a backslash, or the parser reads it as a column edge and the row grows a phantom column.
Tip: a cell full of long prose usually means the table is the wrong shape. Keep cells to a few words and move the explanation into the paragraph below, so the table still fits a phone screen.
Where Markdown tables really work
Pipe tables come from the GFM spec, so support tracks how closely a platform follows it. Here is the picture for the places people paste a table most often.
| Platform | Pipe tables | Colon alignment | Notes |
|---|---|---|---|
| GitHub | Yes | Yes | Native GFM in README files, issues and comments |
| GitLab | Yes | Yes | GFM-based, same syntax as GitHub |
| Yes | Yes | Renders in posts and comments in the current editor | |
| Discord | No | No | Messages show the raw pipes as plain text |
| Notion | On paste | Partly | Pasted Markdown becomes a native Notion table |
| Obsidian | Yes | Yes | Live preview plus a built-in table editor |
| VS Code preview | Yes | Yes | Built-in preview renders GFM tables |
A rule of thumb for any new tool
If a tool advertises GitHub Flavored Markdown, tables work. If it is a chat app with light formatting, assume they do not. The fallback there is a fenced code block, which at least keeps your columns lined up in a monospaced font. Our GFM guide lists the other features that travel with tables.
Three mistakes that break a table
Three failures account for almost every broken table.
1. The divider row is missing
Leave it out and the whole block renders as one literal paragraph of pipes. Nothing warns you first.
Broken Fixed
| Name | Role | | Name | Role |
| Ada | Lead | | ---- | ---- |
| Ada | Lead |
2. A blank line sits inside the table
Markdown treats a blank line as the end of a block. The table stops there, and every row below it turns into ordinary text. Delete the blank line and the rows join up again.
3. A pipe inside a cell is not escaped
A raw | in a cell splits that row into an extra column.
Broken Fixed
| Command | Meaning | | Command | Meaning |
| ------- | -------- | | ------- | -------- |
| a | b | a pipe | | a \| b | a pipe |
One quieter problem is worth knowing. A row with fewer cells than the header raises no error. Renderers pad it with blanks instead, so the table looks slightly wrong rather than plainly broken. The live preview in the editor shows all four cases as you type them.
Faster ways to build a big table
Hand-aligning a twenty-row table wastes an afternoon. Use this routine instead.
- Type the rows with no padding at all. Column widths in the source have no effect on the output.
- If the data already sits in a spreadsheet, copy the cells and drop them into the table to Markdown converter, which swaps the tab characters for pipes.
- Starting from nothing? Fill in the grid in the Markdown table generator and copy the finished block out.
- Keep the column count low. Nine columns are unreadable on a phone, and they get clipped when you save the document as a PDF.
Where Markdown tables stop
Merged cells, fixed column widths and captions all sit outside the syntax. The moment you need one, the right answer is a raw HTML <table>, which GitHub and this site both render. The Markdown tables guide works through that fallback in detail.
After that it is a judgement call rather than a syntax problem. Markdown vs HTML weighs the two ways of writing a table, and the cheat sheet keeps the divider-row pattern one glance away.
Related questions
Try the Editor
Open Editor