Excel to Markdown

How to convert an Excel table to Markdown

rows.page turns up to 1,000 rows of pasted Excel cells, or of a CSV up to 1.5 GB, into a GitHub Flavored Markdown table, free with no signup. Copy the cells, click Paste data, then choose Export > Markdown; pipes are escaped. .xlsx files don't open, so paste the cells or save a CSV first.

.csv.tsv
Drop a file here
Stays in your browserUp to 1.5 GB

No file handy? Open CO2 emissions by country and year (50k rows, 14 MB).

Copy Excel cells to Markdown on rows.page

  1. Select the cells in Excel, header row included, and copy them.
  2. Open rows.page, click Paste data and paste. Excel copies cells as tab-separated text, so they open as a table.
  3. Open the Export menu and choose Markdown. rows.page downloads the table as a Markdown file, ready to paste into a README.md, an issue or your docs.

rows.page can't read a workbook: a dropped .xlsx or .xls file won't open as a sheet, and pushing one returns "This looks like an Excel or zip file. Export it as CSV and push again." To work from a file, save the sheet as CSV UTF-8 (Comma delimited) and drop it on the page. Everything runs in your browser with DuckDB-WASM, and nothing is uploaded unless you press Share.

Ways to convert Excel to Markdown
MethodInputRows in the tableEscapes pipes
rows.page Paste dataCopied cellsFirst 1,000Yes
rows.page fileCSV or TSV saved from Excel, up to 1.5 GBFirst 1,000Yes
pandas to_markdown().xlsx or CSV, needs tabulateAllNo

What the Markdown export writes

  • A header row and a plain | --- | delimiter row, with no column alignment set.
  • The first 1,000 rows of the current view, without hidden columns. The Export menu marks Markdown "first 1,000", but the file itself doesn't say when rows were cut.
  • Pipes inside cells become \| and backslashes become \\, so the columns stay in place.
  • Line breaks inside a cell become a single space, because a Markdown row has to stay on one line.
  • Empty cells stay empty, and list columns are written as JSON text.
markdown
| item | note | price |
| --- | --- | --- |
| Pipe \| tube | line one line two | 25 |
| Bracket |  | 10 |

Trim and reshape the table before exporting

The export follows your current view, so cut the table down first:

  • Hide columns from the column header menu or the Columns panel.
  • Filter rows with country:NL, price:>20, name:* (has a value) or -name:* (empty), or click a histogram bar or a top value in the Columns panel.
  • Click a column name to sort and shift-click to add a second sort, so the rows you need land inside the first 1,000.

To rename headers or reorder columns, type SQL into the same box. The table is called data, and the column names in your result become the Markdown header:

sql
SELECT item AS "Item", price AS "Price"
FROM data
WHERE price > 20
ORDER BY price DESC

Naming the columns also leaves out the hidden __rid row-number column. To drop duplicate rows, use SELECT DISTINCT * EXCLUDE (__rid) FROM data.

Set column alignment after exporting

GitHub Flavored Markdown sets alignment with colons in the delimiter row. rows.page doesn't add them, so edit that row after export:

  • :--- aligns the column left.
  • :---: centers it.
  • ---: aligns it right, which suits numbers.
markdown
| Item | Note | Price |
| :--- | :---: | ---: |
| Pipe \| tube | a \| b | 25 |
| Bracket |  | 10 |

Convert Excel to Markdown in Python with pandas

For more than 1,000 rows, or to script the conversion, use pandas. DataFrame.to_markdown() needs the tabulate package, doesn't escape pipes, prints empty cells as nan and lets a line break split the row, so clean the cells first:

bash
pip install pandas openpyxl tabulate
python
import pandas as pd

df = pd.read_excel('sheet.xlsx').fillna('')
df = df.replace({r'\|': r'\\|', r'\n': ' '}, regex=True)
print(df.to_markdown(index=False))

tabulate right-aligns number columns (---:) and left-aligns text (:---). read_excel also turns text such as 02134 into a number unless you pass dtype={'zip': str}.

What Markdown tables can't hold

  • Merged cells: Markdown has no column or row spans. Excel keeps a merged range's value in its upper-left cell only, so the other cells arrive empty.
  • Formulas and formatting: copied cells carry the values Excel displays, not formulas, colors or bold text.
  • Line breaks: a cell can't span lines, so rows.page joins them with a space. For another separator, run SELECT * EXCLUDE (__rid) REPLACE (replace(note, chr(10), ' / ') AS note) FROM data before exporting.
  • Size: the export stops at 1,000 rows. For a bigger table, press Share and link to the hosted copy instead.

rows.page limits and prices

WhatLimit or price
Open a file in your browserFiles up to 1.5 GB, $0, no account, nothing uploaded
Share a link without an account$0, files up to 100 MB, link deleted 7 days after creation
Free account$0, 10 datasets kept, last 3 versions
Pro$12/month, 100 datasets, files up to 500 MB, private links
Max$39/month, 1,000 datasets, files up to 2 GB, private links

Questions

Does rows.page upload my Excel data?

No. Pasted cells and opened files are read inside your browser with DuckDB-WASM. Nothing is uploaded unless you press Share.

Why won't rows.page open my .xlsx file?

rows.page doesn't read .xlsx or .xls files, and pushing one returns "This looks like an Excel or zip file. Export it as CSV and push again." Copy the cells and click Paste data, or save the sheet as CSV UTF-8 first.

How many rows can the Markdown export hold?

The first 1,000 rows of the current view. For all rows, export CSV, Parquet, JSON or JSONL instead: a filtered view exports every matching row, and a SQL result up to 1,000,000.

How do I share a table that's too big for Markdown?

Press Share ("Upload and get a link") to get a https://rows.page/<id> link. On the hosted page, Copy link (Copy link to this view on mobile) shares the current filter, sort and visible columns. One push is capped at 100 MB, and the link expires after 7 days unless you press Keep it on the dataset page; a free account keeps up to 10 datasets.

Why won't my CSV with euro signs open in rows.page?

A CSV that isn't UTF-8 is read as Latin-1, but a euro sign, curly quotes or long dashes saved in a Windows encoding stop it from opening ("Couldn't open this data"). Save it again as CSV UTF-8 (Comma delimited), or copy the cells and use Paste data, which keeps those characters.