479 byte (minified) CSV parser and builder. Smaller when compressed. Built in ESM only.
Doesn't care about headers, keyed rows, anything but strings. Just supports the CSV spec including multi-line and quoted strings.
Does not support:
\r\n
(old DOS newlines)- streaming
If you need those features, try tiddlycsv, which is a bit bigger. This package is intentionally tiny, mostly to prove a point.
Install via you favourite package manager and import but-csv
.
Has zero dependencies (obviously).
$ npm install but-csv
Parses a CSV into an array of array of strings. Supports varied line lengths. Does not convert to numbers or any other formats.
import { parse } from 'but-csv';
const out = parse('foo,bar,zing\n1,2,3\n4,5');
// out will be [['foo', 'bar', 'zing'], ['1', '2', '3'], ['4','5']]
Only supports passing a string
(not a Buffer
or friends).
Node's operations on string
are so much faster than on raw bytes (10x improvement).
If you're parsing a file, do this:
const f = fs.readFileSync('source.csv', 'utf-8');
const out = parse(f);
Like parse, but you get each row at a time so you can stop early.
import { iter } from 'but-csv';
for (const row of iter('foo,bar,zing\n1,2,3\n4,5')) {
// row will be an array of:
// 1. ['foo', 'bar', 'zing'],
// 2. ['1', '2', '3']
// 3. ['4','5']
}
You can pass any value and it will be stringified before render, useful for numbers. This is unlike the parser above, which only returns strings.
import { build } from 'but-csv';
const out = build([
['hello', 'there"\n'],
[1, 2],
]);
// out will be:
// hello,"there""
// "
// 1,2
Be sure to turn on your bundler's tree-shaking ability (good practice in general), but especially if you're only parsing or building, because the code is separate. Parsing is about 75% of the code, and building 25%.
It's very fast, but doesn't support streaming. To parse multiple copies of 1.csv from here, parsing all at once:
but-csv: 732.908ms
papaparse: 1.337s (1.8x)
csv-parser: 2.283s (3.1x)