If you need a table in your README, the fastest path is to paste your CSV into CSV to Markdown and hit Run. It produces a GFM-compatible table you can copy straight into your README, all inside the browser.
This article covers when README tables make sense, how to generate them from CSV or JSON, and what to watch out for with GitHub Flavored Markdown.
When a README needs a table
Plain text works until the information grows. The following kinds of content read much better as tables:
- API endpoint lists (path, method, description)
- Supported versions or platform compatibility matrices
- Feature comparisons (your project vs. alternatives, or free vs. paid)
- CLI option references
- Environment variable lists with defaults
Bullet lists stretch vertically and make it hard to compare across columns. A table lets readers scan horizontally and spot differences immediately.
Real-world README table examples
The five categories above are abstract. Here is what they actually look like as Markdown tables you can drop into a README today.
CLI options reference — every CLI tool grows a flag list. A table beats a wall of --help text:
| Flag | Default | Description |
| :--- | :--- | :--- |
| `--port` | `3000` | HTTP port to listen on |
| `--host` | `0.0.0.0` | Bind address |
| `--log-level` | `info` | One of `debug`, `info`, `warn`, `error` |
Version compatibility matrix — runtime support is the most common reason to scan a README:
| Runtime | Minimum | Tested up to | Status |
| :--- | ---: | ---: | :--- |
| Node.js | 18.x | 22.x | LTS supported |
| Bun | 1.0 | 1.1 | Best effort |
| Deno | 1.40 | 2.0 | Community |
Feature comparison vs alternatives — used in every "why this library" section:
| Feature | This project | Alternative A | Alternative B |
| :--- | :---: | :---: | :---: |
| Zero dependencies | ✅ | ❌ | ✅ |
| TypeScript types | ✅ | ✅ | ❌ |
| Browser-side | ✅ | ❌ | ❌ |
Each of these is small (3–4 rows, 3–4 columns) on purpose: GitHub renders them without horizontal scroll on mobile, and they stay readable when the README grows.
Markdown table basics
GFM tables use pipe characters as column separators:
| Command | Description |
| --- | --- |
| install | Install dependencies |
| build | Build for production |
| test | Run the test suite |
Row one is the header, row two is the separator, and every row after that is data. Add : to the separator to control alignment (:--- left, :---: center, ---: right).
For a deeper dive into the syntax, see Markdown table syntax.
Generate a README table from CSV
When your data lives in a spreadsheet or a CSV file, use CSV to Markdown:
- Open CSV to Markdown
- Paste your CSV into the left editor (copy-paste from Excel or Google Sheets works too)
- Press Run
- Copy the Markdown table from the right pane into your README


Everything runs in the browser — no data leaves your machine. For more detail on edge cases and escaping, see How to convert CSV to a Markdown table.
Not sure whether the data itself should live in JSON, YAML, CSV, or Markdown? The JSON vs YAML vs CSV vs Markdown comparison cheatsheet breaks down when to use each format.
Create a table from JSON data
Sometimes your data starts as JSON — an API response, a config dump, a log extract. The most reliable route to a Markdown table is to go through CSV first.
For a deeper walkthrough covering arrays, nested objects, and API responses, see How to convert JSON to a Markdown table.
Steps
- Format the JSON with JSON Formatter to verify its structure
- Convert the JSON array to CSV (object keys become column headers, values become row cells)
- Paste the CSV into CSV to Markdown to generate the table
For example, given this JSON:
[
{ "name": "Node.js", "version": "20.x", "status": "LTS" },
{ "name": "Node.js", "version": "22.x", "status": "Current" }
]
The CSV equivalent is:
name,version,status
Node.js,20.x,LTS
Node.js,22.x,Current
Paste that into CSV to Markdown and the table is ready for your README.
Common pitfalls in README tables
Most "broken" README tables boil down to four mistakes. Knowing which one bit you saves a long bisect through Markdown source. The GFM spec §4.10Opens in a new tab requires three things for a table to render: a header row, a delimiter row whose cells contain at least three hyphens each, and a blank line before the table.
Inconsistent column counts
The delimiter row fixes the number of columns. Any row with more cells gets the extras silently dropped; any row with fewer cells gets empty cells appended.
| name | role |
| --- | --- |
| Alice | Engineer | LA ← extra cell, dropped silently
| Bob ← missing cell, rendered blank
GitHub does not warn about this. If the right column of your table is mysteriously empty, count the pipes in the offending row.
Forgotten or short header separator
A common copy-paste failure: the delimiter row has fewer than three hyphens per column, or the entire row is missing. GitHub then renders the source as a literal paragraph instead of a table.
| name | role |
| -- | -- | ← invalid (two hyphens), no table rendered on strict GFM parsers
Stick to three or more hyphens per column. If a table refuses to render on GitHub but works in your editor, this is the first thing to check.
Empty cells in GitHub vs editors
GFM allows truly empty cells:
| feature | basic | pro |
| :--- | :---: | :---: |
| Export PDF | | ✅ |
| API access | | ✅ |
GitHub renders the empty cells correctly. Some editors collapse the row visually because they read consecutive pipes as a syntax error. The Markdown source is fine — the editor preview is wrong. Render on GitHub to confirm.
Pipe | literal inside a cell
A pipe character in a cell terminates the column. Escape it with a backslash, or use the HTML entity |:
| condition | meaning |
| --- | --- |
| `a \| b` | bitwise or |
| `a | b` | same, via entity |
Both render as a | b on GitHub. Backslash is the GFM-standard way; the HTML entity is a safer fallback if your README is processed by a non-GFM toolchain (Hugo, MkDocs).
If your table renders correctly when you paste it on GitHub but looks broken in your local editor, the editor is usually the problem — preview on github.com is the source of truth for any README table.
GFM table quirks on GitHub
GitHub's Markdown renderer behaves differently from general-purpose Markdown editors in a few ways.
Cell line breaks with <br>
The GFM table spec does not allow literal newlines inside cells. A multi-line cell written like this gets flattened to a single line:
| step | description |
| --- | --- |
| 1 | install dependencies
then build |
Use <br> instead — GitHub renders it as a line break inside the cell:
| step | description |
| --- | --- |
| 1 | install dependencies<br>then build |
| 2 | run tests<br>commit the lockfile |
<br> is one of the very small set of HTML tags that survive GitHub's Markdown sanitizer inside tables (see next section). Most editors preview this correctly, but if yours does not, paste the README into a GitHub Gist to verify the actual render.
Limited HTML inside tables
GitHub strips most inline HTML inside table cells for security. <br> works for line breaks, but <span style="...">, <font color>, and similar inline styles are ignored. Do not rely on color or font-size changes inside cells. Block-level tags like <details> work outside tables but not inside cells.
Column alignment
The : alignment syntax in the separator row works as expected on GitHub. Right-aligning numeric columns makes version numbers and prices easier to scan.
| Plan | Monthly |
| :--- | ---: |
| Free | $0 |
| Pro | $10 |
Wide tables and horizontal scroll
Tables with many columns trigger horizontal scrolling on GitHub. If readers will view the README on both desktop and mobile, keep tables to five or six columns, or split them into separate tables.
Frequently asked questions
Can I manage README tables in a spreadsheet?
Yes. Keep the source data in a spreadsheet, export CSV whenever the content changes, and run it through CSV to Markdown to regenerate the table. Paste the result into the README and commit.
Can I put links inside table cells?
Yes. Standard Markdown link syntax [text](url) works inside GFM table cells and renders as clickable links on GitHub.
Wrapping up
Tables make README content scannable. Writing pipes by hand is fine for a few rows, but anything larger calls for automation. CSV to Markdown generates the table from pasted CSV in seconds, so you can spend your time on the content instead of the formatting.