CSV Diff / Compare
Compare two CSV exports row by row — added, removed and changed rows, cell-level detail, optional key-column match — entirely on this device.
Comma-separated header names, in the order they should be joined.
Drop a CSV file into either side — it is read on this device and never uploaded.
Press ? for shortcuts
Do it offline:$ git diff --no-index old.csv new.csv
How to use it
- Paste the older export into side A, the newer one into side B, or drop a file onto either side — a dropped file is read here, and no request carries it.
- Leave matching on Position while the two exports share a row order: the strip above the table counts added, removed, changed and unchanged rows.
- Switch matching to Key column and name what identifies a row — sku, id, email — whenever rows may have been appended or re-sorted since.
- Pick Header name or Position for column alignment when the header rows disagree, and use Ignore case or Trim cell whitespace for cosmetic edits.
- Read the result side by side or unified, step through it with the next and previous controls, then copy the change report, download it, or share a link.
Two exports of the same table, taken a week apart: this page lines them up and reports which rows arrived, which disappeared and which cells moved. Rows match by position, or by a key column such as sku when the newer export came out in a different order. Both sides stay in this tab.
Examples
sku,price,stock
A-1,10.00,4
B-2,20.00,7
change,side,sku,price,stock
Unchanged,A+B,A-1,10.00,4
Changed,A,B-2,20.00,7
Changed,B,B-2,22.50,7
One price moved. Row A-1 matched and stays unchanged; row B-2 is one changed row, marked on the price cell rather than the whole line. In the report a changed row prints twice: side A, then B.
sku,price
A-1,10.00
B-2,20.00
C-3,30.00
change,side,sku,price
Changed,A,B-2,20.00
Changed,B,B-2,22.50
The same three products in a different order, with one real edit. The sku key finds it: one changed row, two untouched, nothing added or removed. Position matching answers with two removed rows, two added and one survivor — true, and useless.
sku,price
A-1,10.00
B-2,20.00
change,side,sku,price,currency
Changed,A,A-1,10.00,—
Changed,B,A-1,10.00,USD
Changed,A,B-2,20.00,—
Changed,B,B-2,20.00,USD
Side B gained a column. Alignment by header name keeps the union of both header rows, so currency shows an em dash where side A has no such cell, and every row reads as changed — each did gain a value.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Cells are text, never numbers
007 and 7 differ; so do 1 and 1.0, and 10.00 and 10. No cell is read as a number, rounded or given a tolerance, because equating those hides the edits most worth catching in a price column.
Line endings alone are not a difference
A side saved with CRLF endings and the same side saved with LF compare as equal: the ending is structure, not content. A quoted cell holding a line break stays one cell.
Key columns: empty values, repeats, and more than one
An empty key value is a real key and matches other empty keys. A repeated key is not refused: those rows pair in the order they appear, and a warning counts them, capped at twenty. Name several columns to make a row unique.
Very large comparisons stay finite
Rows align one by one until a ten-second budget is spent, then the result degrades to coarse blocks with a warning, rather than freezing the tab. Sides that would line up more than four million cells are declined; 100 MB is the ceiling per side, and a share link stops at 8 KB compressed.
Common errors
Key column “sku” is not in side B's header row — pick a column both sides have.- The column is looked up by name, so position alignment cannot rescue it. Usually the newer export renamed it: pick a column both sides carry.
Side B has no header row, so there is no column name to match rows on — turn its header row on, or match rows by position.- That side was read as pure data — its first record really is data, or its header switch is Off. Naming columns needs headers on both sides; position matching does not.
Key "A-1" appears 2 times in side A and 2 times in side B — those rows were paired in the order they appear; add another key column to make each row unique.- A warning, not a refusal — the comparison still runs. Repeats pair in order inside their group, which is a guess: the first A-1 here need not be the first there.
The two sides do not have the same columns: "currency" only in side B — the missing side shows an empty cell, so rows carrying those columns cannot match; match columns by position if the sides only differ in header names.- Printed whenever the two header rows are not the same set. If the same columns are merely spelled differently, position alignment ignores names and compares column 1 with column 1.
Lining these two files up would compare 4,004,000 cells, more than the 4,000,000-cell limit for this tool — compare fewer rows or columns at a time.- The refusal arrives before any grid is built, and the figure is what your own two files would cost: rows on both sides times aligned columns. Nothing is trimmed.
Side A input is larger than the 100 MB limit for this tool. For bigger files use the CLI: git diff --no-index old.csv new.csv- The page-side ceiling, checked before a character is parsed, naming this page's command-line equivalent. It applies per side; the other pane keeps its text.
FAQ
Why does re-sorting a CSV make almost every row look changed?
Position matching pairs the first data row with the first, the second with the second, and so on. Re-sort one side and those pairings stop describing the same records, so the answer collapses into removals and additions. Name a key column and rows pair by their identifier, so a row that moved reads as moved.
What exactly counts as one changed cell?
One aligned column whose two values are not equal under the options in force: values are read as text, and Ignore case and Trim cell whitespace decide whether ADA and ada count. Rows and cells are tallied separately — a matched pair that differs anywhere is one changed row, and each differing column inside it adds one cell.
Are both files uploaded anywhere to be compared?
No. Reading, matching and the report all happen in this tab; watch the network panel while comparing and no request carries a row of either side. Sharing puts the state in the address fragment, the part after the # a browser keeps to itself.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Compare now, or re-run.
- ⌘/Ctrl + S
- Download the change report.
- ⌘/Ctrl + C
- Copy the report, nothing selected.
- ⌘/Ctrl + Shift + C
- Copy even with a selection.
- s
- Swap sides A and B.
- n
- Go to the next difference.
- p
- Go back one difference.
- t
- Cycle to the next theme.
- ? or ⌘/Ctrl + /
- Open the shortcut help.
- Esc
- Close the top overlay.