CSV row diff
csv-row-diff · version 1.0.0 · CSV & tables · free, no key needed
Compare two CSV documents with identical headers by unique key tuples and report added, removed, and changed rows.
Use when you need to: csv row diff · diff csv rows by keys · compare keyed csv rows.
Supported
- csv row diff
- diff csv rows by keys
- compare keyed csv rows
Not supported
- outer join
- fuzzy matching
- numeric comparison
- case-insensitive diff
- unkeyed row diff
- read files
- fetch urls
Behavior
- left and right must share identical headers in the same order.
- keys is a non-empty unique subset of those headers, at most 32 names.
- Duplicate key tuples on either side are rejected because the diff is undefined.
- Rows are classified by exact key-tuple membership and exact remaining-column string tuples.
- added contains right-only keys in right row order; removed and changed follow first-seen left key order.
- changed rows are the right-side (new) values with the original headers; no change column is added.
- No trimming, case folding, type coercion, or numeric comparison is performed.
- Empty documents without headers are rejected; header-only inputs emit the shared header and zero counts.
- The first header name may not begin with U+FEFF because it is ambiguous with a CSV byte-order mark.
Input
left(string, required): max length 256000right(string, required): max length 256000keys(array of string, required): min items 1; max items 32; each min length 1
Output
added(string, required)removed(string, required)changed(string, required)counts(object, required)
Limits
- max input bytes: 256000
- max data rows: 5000
- max columns: 256
- max header name bytes: 256
- max keys: 32
- max output bytes: 1048576
Example
Request input:
{
"left": "id,name,city\n1,Ada,London\n2,Lin,Paris\n3,Zoe,Berlin\n",
"right": "id,name,city\n1,Ada,London\n2,Lin,Rome\n4,Bob,Oslo\n",
"keys": [
"id"
]
}
Response:
{
"result": {
"added": "id,name,city\n4,Bob,Oslo\n",
"removed": "id,name,city\n3,Zoe,Berlin\n",
"changed": "id,name,city\n2,Lin,Rome\n",
"counts": {
"added": 1,
"removed": 1,
"changed": 1,
"unchanged": 1
}
}
}
How to call it
MCP
Connect https://computefirst.net/mcp (setup), then call execute with:
{
"id": "csv-row-diff",
"version": "1.0.0",
"input": {
"left": "id,name,city\n1,Ada,London\n2,Lin,Paris\n3,Zoe,Berlin\n",
"right": "id,name,city\n1,Ada,London\n2,Lin,Rome\n4,Bob,Oslo\n",
"keys": [
"id"
]
}
}
HTTP (no key)
curl -X POST https://computefirst.net/v1/tools/csv-row-diff/versions/1.0.0/execute \
-H "Content-Type: application/json" \
-d '{"left":"id,name,city\n1,Ada,London\n2,Lin,Paris\n3,Zoe,Berlin\n","right":"id,name,city\n1,Ada,London\n2,Lin,Rome\n4,Bob,Oslo\n","keys":["id"]}'
The machine-readable contract is at /v1/tools/csv-row-diff/versions/1.0.0.
CLI
node cli.mjs run csv-row-diff 1.0.0 --input input.json --base-url https://computefirst.net
Get the client at /clients/cli/.
Related tools
- CSV reconcile: Reconcile two CSV documents by key columns, reporting full population totals and bounded samples for added, removed, changed, invalid-key, and ambiguous rows.
- CSV add row number: Prepend a 1-based row_number column of canonical integer strings.
- CSV anti join: Keep left CSV rows whose exact key tuples do not appear in the right document.
- CSV dedupe: Remove duplicate CSV data rows while preserving the first occurrence.
- CSV group count: Count CSV rows by exact named-column tuples in first-seen order.
- CSV slice rows: Take a contiguous window of CSV data rows by offset and limit, keeping the header.