Version control for CSV

Version control for CSV files, without git

Free versioning for data files, no signup, no git. Push a CSV up to 100 MB with curl, push it again, keep up to 20 versions and see what changed between them: rows new, gone and changed, columns added or removed. Works for CSV, TSV, JSON, JSONL and Parquet; 365 days of history on Max.

.csv.tsv.json.jsonl.parquet
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).

Why git is the wrong tool for a CSV

Git diffs lines, and a CSV re-exported from a database or a spreadsheet changes the order of rows, the quoting or the float formatting without changing a single fact. The result is a 50,000-line diff nobody reads, a repo that grows by the full file every commit, and git LFS once the file passes 100 MB.

Here a version is a file, not a patch. Pushing the same bytes twice adds nothing and answers unchanged: true. Pushing a changed file adds one version and the comparison is done on rows, not lines.

Two commands and you have history

curl -T data.csv https://rows.page creates version 1 and prints the public link plus an owner link with a token. Next time, curl -T data.csv -H "Authorization: Bearer rpt_..." https://rows.page/<id> makes version 2. The JSON response carries a changes block with the previous version, the row delta, columns added and removed, and a link to the comparison.

Name a key column on the push, ?id_column=sku, and the comparison can match rows across versions. Without a key you still get new and gone rows; with it you also get changed rows.

What the page shows for every version

Open the link and the banner reads something like +120 new, 8 gone, 15 changed vs v1, matched by sku, plus +2 columns or 1 column gone when the schema moved. Rows are compared by hashing the columns both versions share, so a reordered export with the same content shows 0 changes.

If no key was named, the page suggests columns that look unique in both versions (ids, codes, emails) and you pick one with a click. Previous versions up to 64 MB are compared automatically when the page opens; bigger ones compare when you ask. Any older version opens from the version menu.

Retention and limits

Without an account a link holds up to 20 versions and is deleted 7 days after creation. A free account keeps 10 datasets for good with the last 3 versions open; older versions stay stored for 90 days but locked. Pro ($12/month) opens 90 days of versions, 100 datasets, files up to 500 MB and private datasets; Max ($39/month) opens 365 days, 1,000 datasets, 2 GB files.

Pushes are rate limited to 10 per minute without an account and 120 per minute with an API key, and anonymous pushes are capped at 50 and 1 GB per day per IP. Nothing is deleted when a limit hits: the push answers 402 and names the plan that fits.

Nightly jobs, pipelines and agents

On a plan, an API key (rpk_...) and POST /api/v1/push?key=nightly-report upsert the same dataset every run, so a cron job or a GitHub Actions step always writes the next version of one link instead of minting new ones. Add ?source=, ?run= and ?commit= and every version records where it came from.

Agents do the same through the MCP server at rows.page/mcp: push returns the version and the change summary, get_dataset reads rows back with filters, so a model can see what changed since its last run without diffing anything itself.

Limits for versioning CSV files

WhatLimit or price
Price$0, no account for public links
File size per version100 MB per push; 500 MB on Pro and 2 GB on Max through the API
Change summaryRows new, gone and changed (with a key), columns added and removed
Automatic comparisonPrevious version up to 64 MB; bigger ones compare on click
Key columnSet with ?id_column= on push or picked on the page; must be unique
Versions without an accountUp to 20, link deleted 7 days after creation
Push rate10 per minute without an account, 120 per minute with an API key
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

Can I compare two CSV files I have on my laptop?

Push the old one, then push the new one to the same link, and open it. You get the counts of new, gone and changed rows and the column changes. It is a change summary per version, not a side-by-side cell diff.

What counts as a changed row?

A row whose key value exists in both versions but whose other shared columns hash differently. Without a key column there are only new and gone rows, and an edited row shows up as one gone and one new.

What if my key column has duplicates?

The banner says so and falls back to new and gone counts. Pick another column, or add a composite key to the export, like SELECT sku || '-' || region AS key, * FROM data, before pushing.

Can I download an old version?

Yes. Every version is immutable and its original file is served at /<id>/v<n>/raw.csv, as long as your plan still opens that version.

Is my data private?

Public links are unguessable and marked noindex, but anyone with the link can open them. Private datasets, which only the owner can read, come with Pro and Max.

More tools

Pushing data from a script or agent? Read the docs.