Markdown Table Syntax: The Complete How-To Guide
A markdown table uses pipes (|) to separate columns and a row of dashes (---) to split the header from the body. That second line is what tells the renderer "this is a table" instead of ordinary text. Here is the smallest working example:
| Name | Role |
| --- | --- |
| Alice | Writer |
| Bob | Editor |
That renders as a two-column table with a bold header row and two data rows below it. The rest of this guide covers the full markdown table syntax: column alignment, formatting inside cells, escaping pipes, multi-line content, and the rendering quirks that trip people up. Every rule comes with a copy-paste block.
If you write in plain text a lot, keep our markdown cheat sheet open in another tab, since tables are one small part of the wider format. Tables also behave differently once you move into MDX and JSX components, and the tool you draft in matters too: a good markdown editor will auto-align columns as you type. For teams standardizing on plain-text docs, this fits the broader docs-as-code workflow.
What is the basic markdown table syntax?
Every markdown table has three parts: a header row, a delimiter row, and one or more body rows. The header row names your columns. The delimiter row is the line of dashes and pipes directly beneath it. The body rows hold your data. You need at least three dashes per column in the delimiter for most renderers to accept it.
| Header 1 | Header 2 | Header 3 |
| -------- | -------- | -------- |
| Cell A | Cell B | Cell C |
| Cell D | Cell E | Cell F |
The columns do not have to line up in your raw text. The example above is spaced out for readability, but |Header 1|Header 2| with no spacing renders identically. What matters is that each row has the same number of pipes. A row with too few cells leaves blanks; a row with too many gets truncated by most renderers.
How to create a table in markdown, step by step
If you are building a table by hand, this order keeps it valid:
- Write your header row first, wrapping each column name in pipes:
| Product | Price | Stock |. - Add the delimiter row underneath with three dashes per column:
| --- | --- | --- |. Match the pipe count exactly. - Add one body row per record, keeping the same number of cells in each.
- Leave a blank line before and after the table so the renderer separates it from surrounding paragraphs.
That last step is the one people skip. Many parsers, including GitHub's, will not recognize a table if it is glued directly to a paragraph above it. A single empty line fixes most "my table renders as plain text" reports.
How to align columns in a markdown table
You control column alignment with colons in the delimiter row. The colon's position relative to the dashes sets the alignment for that entire column. This is the part of markdown table formatting most people miss, because the syntax lives in a row you rarely think about.
| Left | Center | Right |
| :------- | :------: | -------: |
| apple | banana | cherry |
| 1 | 22 | 333 |
Here is what each colon pattern does:
:---puts the colon on the left, which forces left alignment. This is also the default when you use no colon at all.:---:puts a colon on both sides, which centers the column.---:puts the colon on the right, which right-aligns the column. This is the standard choice for numbers and currency.
The width of the dashes has no effect. :-: and :--------: both center a column. Use whatever keeps your raw text readable. Right-aligning numeric columns makes decimal points and digit counts easier to scan in the rendered output.
Formatting inside table cells
Inline markdown works inside cells, so you can add emphasis, code, and links without breaking the table. Bold with **text**, italics with *text*, inline code with backticks, and standard link syntax all render normally.
| Feature | Status | Docs |
| --- | --- | --- |
| **Search** | `stable` | [Guide](/search) |
| *Widgets* | `beta` | [Guide](/widgets) |
Block-level elements are the exception. You cannot put headings, bullet lists, blockquotes, or fenced code blocks inside a table cell using normal markdown. The pipe-and-dash syntax has no room for line breaks, so anything that needs its own line has to be faked. The next section covers how to work around that.
How to escape pipes and special characters
A literal pipe character inside a cell breaks the table, because the renderer reads it as a new column boundary. To show a real | in your text, escape it with a backslash: \|. This is the single most common cause of a table that renders with the wrong number of columns.
| Command | Description |
| --- | --- |
| `a \| b` | Pipe a into b |
| `grep x \| wc` | Count matches |
If backslash escaping fails in a particular renderer, the HTML entity | produces the same pipe character and is read by every parser. Backticks alone do not protect a pipe: code spans still need the pipe escaped inside a table. Backslashes also escape other markdown characters normally, so \* shows a literal asterisk inside a cell.
Nested content and multi-line cells
Markdown table cells cannot contain real line breaks, so multi-line content needs the HTML <br> tag. Drop <br> wherever you want a visual line break inside a single cell, and the surrounding table stays valid.
| Step | Instructions |
| --- | --- |
| 1 | Install the CLI<br>Run `npm install` |
| 2 | Add your key<br>Restart the server |
For a list inside a cell, combine <br> with a bullet character, since real markdown lists will not render there: - item one<br>- item two. When a cell needs genuinely rich content (nested tables, code blocks, images with captions), that is a signal the data has outgrown a markdown table. At that point an HTML <table> or a different layout serves you better than fighting the syntax.
GitHub markdown tables vs other renderers
Tables are not part of the original Markdown spec. They come from extended flavors, and support varies. A GitHub markdown table uses GitHub Flavored Markdown (GFM), which is the most widely copied dialect and the one most tutorials assume. GFM tables render in READMEs, issues, pull requests, and gists.
| Renderer | Table support | Notes |
|---|---|---|
| GitHub (GFM) | Full | Alignment, inline formatting, pipe escaping |
| GitLab | Full | GFM-compatible, plus multiline cells |
| CommonMark (strict) | None | Tables are an extension, not core spec |
| Docusaurus / MDX | Full | GFM tables plus JSX in cells |
| Obsidian | Full | Live preview auto-formats columns |
The practical takeaway: if your table works on GitHub but breaks somewhere else, the target renderer probably uses strict CommonMark or an older parser. Check whether the platform advertises "GitHub Flavored Markdown" support. If it does, GFM table syntax will work. If it only claims "Markdown," test a small table before writing a large one.
Once your docs live in a real documentation site rather than a single README, table rendering stops being your problem to babysit. A platform like Docsio generates a Docusaurus-based docs site from your existing content, and Docusaurus ships with GFM tables built in, so alignment, escaping, and inline formatting render the same way every publish. You write the markdown table; the build handles the rest.
Common markdown table rendering problems
Most table bugs come down to a handful of causes. When a table refuses to render correctly, work through this list before rewriting it:
- The table renders as plain text. You are missing the blank line above the table, or the delimiter row does not have enough dashes. Every column needs at least
---. - Columns are off by one. An unescaped pipe inside a cell is being read as a column boundary. Escape it with a backslash.
- Alignment is ignored. The renderer does not support GFM alignment, or a colon is on the wrong side of the dashes. Recheck the delimiter row.
- Rows are cut short. One row has fewer pipes than the header. Match the cell count across every row, using empty cells where needed.
- Extra column appears. A stray trailing pipe or a pipe inside untagged text is adding a phantom column.
Keeping the pipes visually aligned in your raw text does not change the output, but it makes these errors far easier to spot. This is exactly why editor auto-formatting is worth having: it lines everything up so a missing pipe jumps out.
Using a markdown table generator
Writing wide tables by hand gets tedious fast, and that is where a markdown table generator earns its place. Tools like TablesGenerator.com and Table to Markdown give you a spreadsheet-style grid, then output clean markdown you paste into your file. They handle alignment, escaping, and pipe counting for you.
Generators are most useful in two situations: converting an existing spreadsheet or HTML table into markdown, and building a table with many columns where manual pipe-counting invites errors. For small tables, typing them by hand is faster than switching tools. For anything past four or five columns, a generator or an auto-formatting editor saves real time and prevents the off-by-one pipe bugs above.
When markdown tables become hard to maintain
Markdown tables are excellent for small, static comparisons: a feature grid, a config reference, a short pricing breakdown. They start to hurt when the data grows wide, changes often, or needs content that does not fit on one line. A table with twelve columns is unreadable in raw text and painful to edit, because every change means recounting pipes across every row.
When you hit that wall, you have three options. Move the data to a real HTML table if you only need richer cell content. Split one wide table into several focused ones grouped by topic. Or, if the data is genuinely tabular and large, keep it in a source like a CSV and render it separately. Knowing when to stop using a markdown table is part of writing good docs, a theme we cover in how to write documentation.
Frequently asked questions
How do you create a table in markdown?
Write a header row with column names separated by pipes, add a delimiter row of dashes below it with at least three dashes per column, then add your data rows using the same number of pipes. Leave a blank line before and after the table so the renderer detects it correctly.
How do you align columns in a markdown table?
Add colons to the delimiter row. A colon on the left of the dashes left-aligns the column, colons on both sides center it, and a colon on the right right-aligns it, which suits numbers. The dash count does not affect alignment, only the colon position.
Can you put a line break inside a markdown table cell?
Yes, but not with a real newline, which breaks the table. Use the HTML br tag wherever you want a line break inside a cell. Combine it with a bullet character to simulate a short list. For genuinely rich content, an HTML table is the better choice.
How do you escape a pipe character in a markdown table?
Escape a literal pipe with a backslash, placing the backslash directly before the pipe wherever you need the character to appear as text rather than a column boundary. If a specific renderer ignores the backslash, use the HTML entity for a pipe instead, which every markdown parser reads.
Do markdown tables work everywhere?
No. Tables are not part of the original Markdown spec and come from extensions like GitHub Flavored Markdown. They render on GitHub, GitLab, Obsidian, and most docs platforms, but strict CommonMark parsers ignore them. Confirm your target supports GFM before relying on table syntax.
