To create a Markdown table, put a pipe | between the cells of each row, and add a row of dashes --- right below the header row. That’s all you need:
| Name | Age | |------|-----| | Erik | 40 | | Mary | 53 |
The result:
| Name | Age |
|---|---|
| Erik | 40 |
| Mary | 53 |
This works on GitHub, GitLab, Obsidian, Jupyter notebooks, VS Code’s preview, and most other modern Markdown tools. Below, I’ll show you how to align columns, and then go through everything tables can’t do out of the box (pipes in cells, line breaks, lists, merged cells) and the workarounds that do work.
A bit of background: tables are not part of the original Markdown, and they’re not in the CommonMark spec either. They’re an extension that came from PHP Markdown Extra and was later written down in the GitHub Flavored Markdown (GFM) spec. So when I say “Markdown table” in this article, I mean this GFM pipe-table syntax. If a tool claims Markdown support, it almost always supports these tables, but when in doubt, simply try it.
A basic Markdown table
A table is ‘drawn’ using something resembling ASCII art. You can make it look as pretty or as ugly as you want:
| Item | Price | # In stock | |--------------|-----------|------------| | Juicy Apples | 1.99 | *7* | | Bananas | **1.89** | 5234 |
The result:
| Item | Price | # In stock |
|---|---|---|
| Juicy Apples | 1.99 | 7 |
| Bananas | 1.89 | 5234 |
The rules are simple:
- The first row is always the header row. You can’t leave it out (see the workaround for headerless tables below).
- The second row, the delimiter row, separates the header from the rest. In GFM, one dash per column is enough, but I use three or more because that’s easier to read in plain text.
- Separate cells with a pipe symbol:
|. The pipes at the start and end of a row are optional. - The header row and the delimiter row must have the same number of cells, or you won’t get a table at all. Body rows are more forgiving: missing cells are left empty, and extra cells are ignored.
- Put an empty line before and after the table. A line of text directly below a table becomes an extra row.
- Cells can contain inline Markdown, like bold, italics, code, and links. See our Markdown cheat sheet for all the formatting you might need.
You don’t need to make the table look pretty. This gives you exactly the same result as the table above:
Item | Price | # In stock ---|---|--- Juicy Apples | 1.99 | *7* Bananas | **1.89** | 5234
I usually type tables the quick way and let my editor line them up afterwards. More on that in the section on generators and formatters.
Aligning columns
You can align columns to the left, center, or right. Alignment is specified with colons around the dashes in the delimiter row, below the header cell:
- To align left, add a colon to the left, like
:---(without any colons, most renderers align left too) - For right alignment, add a colon to the right, like:
---: - And finally, for center alignment, add two colons, like:
:---:
Here’s our product table again, with center-aligned prices and right-aligned stock information. Note that I nicely aligned the text in the entire column, but you don’t have to:
| Item | Price | # In stock | |--------------|:-----:|-----------:| | Juicy Apples | 1.99 | 739 | | Bananas | 1.89 | 6 |
The result:
| Item | Price | # In stock |
|---|---|---|
| Juicy Apples | 1.99 | 739 |
| Bananas | 1.89 | 6 |
Alignment always applies to a whole column. There’s no Markdown syntax to align a single cell. If you need that, you’ll have to write the table in HTML.
Formatting, code, links, and images in cells
Cells can contain any inline Markdown: bold, italics, strikethrough, inline code, links, and images. Here’s a small example:
| Syntax | Example | |-----------------|----------------------------------------| | Bold and italic | **bold** and *italic* | | Strikethrough | ~~old price~~ new price | | Inline code | `npm install` | | Link | [Cheat sheet](https://markdown.land/markdown-cheat-sheet) |
The result:
| Syntax | Example |
|---|---|
| Bold and italic | bold and italic |
| Strikethrough | |
| Inline code | npm install |
| Link | Cheat sheet |
Images work the same way:  inside a cell shows the image in that cell. What you can’t put in a cell are block elements: headings, lists, blockquotes, code blocks, or multiple paragraphs. A cell must fit on one line of Markdown. The next section shows how to get around that.
Limitations and workarounds
Markdown tables are deliberately simple. Here are the things people run into most, and what I do about them. Several workarounds use a bit of HTML, which works on GitHub, GitLab, and most other platforms, but not on platforms that strip all HTML.
Escaping a pipe character in a cell
Since the pipe separates cells, a literal | in your text splits the cell in two. Escape it with a backslash: \|.
| Operator | Meaning | |------------|----------------------| | `a \|\| b` | logical OR | | a \| b | a pipe in plain text |
The result:
| Operator | Meaning |
|---|---|
a || b | logical OR |
| a | b | a pipe in plain text |
There’s a catch with inline code. In GitHub Flavored Markdown, the table is split into cells before code spans are processed, so you need to escape pipes even inside backticks. GitHub then removes the backslash, so `a \| b` displays as a | b. Python-Markdown (used by MkDocs) works differently: pipes inside backticks don’t split cells there, and an escaped pipe in code keeps its backslash. So if your docs have to render in both, test it. Outside of code, the HTML entity | is another way to write a pipe.
Line breaks in a cell
Pressing Enter inside a cell ends the row, so you can’t break a line the normal way. Use the HTML <br> tag instead (my article on Markdown line breaks explains why):
| Name | Address | |------|----------------------------------| | Erik | Main Street 1<br>1234 AB Amsterdam |
The result:
| Name | Address |
|---|---|
| Erik | Main Street 1 1234 AB Amsterdam |
Lists in a cell
You can’t put a Markdown list in a table cell. Where HTML is allowed, like on GitHub, you can write the list in HTML instead, as long as it stays on one line:
| Fruit | Good for | |---------|-------------------------------------------| | Bananas | <ul><li>Smoothies</li><li>Baking</li></ul> |
The result:
| Fruit | Good for |
|---|---|
| Bananas |
|
If HTML isn’t allowed, a poor man’s list with • characters and <br> tags often looks good enough. Or ask yourself if the content really belongs in a table.
Merged cells (colspan and rowspan)
Markdown tables have no way to merge cells. If you need a cell that spans multiple columns or rows, write the whole table in HTML with the colspan and rowspan attributes. GitHub keeps both attributes:
<table>
<thead>
<tr><th>Fruit</th><th>Variety</th><th>Price</th></tr>
</thead>
<tbody>
<tr><td rowspan="2">Apples</td><td>Red</td><td>1.99</td></tr>
<tr><td>Green</td><td>2.49</td></tr>
<tr><td colspan="2">Total</td><td>4.48</td></tr>
</tbody>
</table>
The result:
| Fruit | Variety | Price |
|---|---|---|
| Apples | Red | 1.99 |
| Green | 2.49 | |
| Total | 4.48 | |
If you use Pandoc, its grid tables can span cells without HTML. See Pandoc’s other table syntaxes below.
Tables without a header row
GFM requires a header row. The usual workaround is a header row with empty cells:
| | | |------|------| | Erik | 40 | | Mary | 53 |
The result:
| Erik | 40 |
| Mary | 53 |
Depending on the stylesheet, you’ll still see a thin, empty header row. If you want no header at all, use an HTML table without a <thead>.
Tables without leading and trailing pipes
The outer pipes are optional, so this is a valid table:
Name | Age --- | --- Erik | 40
There’s one trap: a single-column table needs at least one pipe per line. Without pipes, Name followed by --- is a heading in Markdown, not a table. I always write the outer pipes; it’s clearer and avoids these surprises.
Wide tables
Markdown has no syntax for column widths or wrapping. Every cell is one line of source, so long text makes the source hard to read, and the rendered table may get wider than the page. On GitHub, a table that’s too wide gets a horizontal scrollbar. Things that help:
- Keep cells short, and move long explanations to a paragraph or footnote below the table.
- Use
<br>to break long cells over multiple lines. - Use reference-style links (
[docs][1]) so long URLs don’t bloat the cells. - Swap rows and columns if you have many columns and only a few rows.
Center a table in Markdown
Believe it or not, there’s no Markdown syntax to center a table. You’ll need to resort to HTML, and what works depends on the platform (GitHub strips style attributes, for example). In my article on centering stuff, I cover three different methods to center a table in Markdown.
Markdown table generators and formatters
Markdown tables are not difficult to create, but typing them by hand is tedious, and a mistake is made easily. Luckily, several people built Markdown table generators. Here’s a list (ordered by my preference):
- TableConvert.com: an online editor that converts between Markdown, Excel, CSV, JSON, SQL, and more
- TablesGenerator.com: a spreadsheet-like editor with a File > Paste table data option
- Markdown Table Maker: allows you to convert CSV or other delimited data into a table quickly
Excel or Google Sheets to Markdown
Select the cells in Excel or Google Sheets and copy them. Then paste them into one of the generators above: TableConvert has an Excel to Markdown converter with a paste box, and in TablesGenerator you use File > Paste table data. Both turn your cells into a Markdown table you can copy back. The first row of your selection becomes the header row, so include the column names.
Formatting tables in VS Code
If you write Markdown in VS Code, I recommend the Markdown All in One extension. Among other things, it includes a table formatter: type your table the quick and ugly way, run Format Document, and it lines up all the pipes for you.
Tables from SQLite
If you happen to use SQLite, you might be delighted to learn that the sqlite3 shell can output query results as a Markdown table directly. Read my article on creating SQLite Markdown output to learn how, including the gotchas with pipes and newlines in your data.
Other table syntaxes in Pandoc
Pandoc supports the pipe tables from this article, plus three other table syntaxes:
- Simple tables: columns lined up with spaces, no pipes. Alignment follows from where the header text sits above the dashes.
- Multiline tables: like simple tables, but a row can span several lines of text.
- Grid tables: drawn with
+,-,=, and|. Cells can contain block elements like lists and code blocks, and cells can span rows and columns.
Here’s a simple table and a grid table:
Fruit Price ------- ------ Apples 1.99 Bananas 1.89 +---------+--------------------+ | Fruit | Good for | +=========+====================+ | Bananas | - Smoothies | | | - Baking | +---------+--------------------+
Pandoc also lets you add a caption to any of these tables with a line that starts with Table: or just :. Keep in mind these syntaxes are Pandoc-only. GitHub and most other platforms won’t render them as tables, so stick to pipe tables for READMEs.
Frequently asked questions
Do Markdown tables work everywhere?
Almost. Tables are a GFM extension, not part of CommonMark or the original Markdown, so a strict CommonMark parser shows them as plain text. In practice, GitHub, GitLab, Obsidian, Jupyter, VS Code, MkDocs, and Pandoc all support them. The workarounds that use HTML, like <br> and merged cells, only work where HTML is allowed.
How many dashes do I need in the delimiter row?
In GFM, one dash per column is enough: |-|-| works. Other parsers can be stricter, and three dashes is the common convention, so I stick with ---.
Can I add a caption to a Markdown table?
Not in GFM. You can put a short line of text above or below the table, or use an HTML table with a <caption> element. Pandoc does support captions with its Table: syntax.
Can I set column widths?
No. The renderer decides the width based on the content. The number of dashes in the delimiter row has no effect on GitHub. If you need fixed widths, use an HTML table, keeping in mind that GitHub strips style attributes.
How do I add a table to my README?
Exactly as shown in this article. GitHub renders pipe tables in README.md files, issues, pull requests, and wikis. GitHub Docs has a short page on organizing information with tables, and my article on writing a good README.md covers the rest of a README.
Conclusion
You’ve learned how to create tables in Markdown, how to align columns, and how to work around the limitations: escaped pipes, <br> for line breaks, HTML for lists and merged cells, and an empty header row for headerless tables. We’ve also looked at table generators, Excel and Google Sheets conversion, and Pandoc’s other table syntaxes. For the rest of the Markdown syntax, keep the Markdown cheat sheet handy.
