jtcsv
v3.2.0
Published
Complete JSON<->CSV and CSV<->JSON converter for Node.js and Browser with streaming, security, Web Workers, TypeScript support, and optional ecosystem (zero-deps core)
Maintainers
Keywords
Readme
jtcsv — JSON ↔ CSV toolkit for Node.js and browser
JSON ↔ CSV in Node and the browser. Streaming. Tree-shakable. 18 KB gz core. Zero deps.
npm install jtcsvimport { csvToJson, jsonToCsv } from 'jtcsv';
const csv = jsonToCsv([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
const rows = csvToJson(csv, { parseNumbers: true });
// rows: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]That's the whole API in 4 lines. Read on for streaming, NDJSON/TSV, worker threads, framework adapters, and the full subpath layout.
Why jtcsv
| | jtcsv | papaparse | csv-parse | fast-csv |
|---|:---:|:---:|:---:|:---:|
| Speed (1M rows, fastPath) | 836 ms | 1752 ms | 2659 ms | 3491 ms |
| Bundle (gz, parser only) | ~18 KB | ~9 KB | ~14 KB | ~30 KB |
| TypeScript types | ✅ first-class | DT only | ✅ | DT only |
| CSV-injection guard by default | ✅ | — | — | — |
| Web Workers (browser) | ✅ subpath | — | — | — |
| Worker threads (Node) | ✅ opt-in | — | — | — |
| Streaming | ✅ Transform + iterator | ✅ step | ✅ Transform | ✅ Transform |
| NDJSON / TSV first-class | ✅ | — | — | — |
| --provenance signed publish | ✅ | — | — | — |
| Subpath imports | ✅ 9 entries | — | — | — |
Reproduce the bench: npm run benchmark:vs. CI publishes the latest
numbers to
github.io/jtcsv/dev/bench
on every merge to main and fails PRs that regress more than 25 %.
Subpath imports (tree-shaking)
Pay only for what you import. Each subpath has its own package.json#exports
entry point, so bundlers ship just the code you use.
| Import path | Use case | Cost (gz, with deps) |
|-----------------------|---------------------------------------|---------------------:|
| jtcsv/csv | CSV → JSON parse | ~18 KB |
| jtcsv/json | JSON → CSV serialize | ~8 KB |
| jtcsv/streams | Node Transform stream helpers | ~10 KB |
| jtcsv/ndjson | NDJSON parse + emit | ~4 KB |
| jtcsv/tsv | TSV parse + emit (uses CSV core) | ~35 KB |
| jtcsv/errors | error classes only (instanceof checks) | ~3 KB |
| jtcsv (full barrel) | everything | ~44 KB |
| jtcsv/browser | browser-safe full bundle | ~15 KB ESM / 16 KB UMD |
| jtcsv/plugins | plugin manager | — (Node-only) |
| jtcsv/schema | schema validator | — (Node-only) |
// Smallest possible import — just what you need.
import { csvToJson } from 'jtcsv/csv';
import { jsonToCsv } from 'jtcsv/json';
import { createCsvToJsonStream } from 'jtcsv/streams';Quick recipes
Parse a file (Node)
import { readCsvAsJson } from 'jtcsv/csv';
const rows = await readCsvAsJson('./data.csv', { parseNumbers: true });Stream a 1 GB file (Node)
import { createReadStream } from 'fs';
import { pipeline } from 'stream/promises';
import { createCsvToJsonStream } from 'jtcsv/streams';
await pipeline(
createReadStream('./big.csv'),
createCsvToJsonStream({ parseNumbers: true }),
async function* (rows) {
for await (const row of rows) yield row; // your per-row logic
},
);Async iterator (lazy parse)
import { csvToJsonIterator } from 'jtcsv/csv';
for await (const row of csvToJsonIterator(csv, { fastPathMode: 'compact' })) {
console.log(row);
}Worker threads (opt-in, Node)
import { csvToJsonAsync } from 'jtcsv';
// Parses across N worker threads when the input is large enough
// to amortize spawn overhead (~1 MB / 5 K rows). Silent sync fallback
// otherwise. workerCount: 0 = os.availableParallelism().
const rows = await csvToJsonAsync(bigCsv, {
parseNumbers: true,
useWorkers: true,
workerCount: 4,
});Browser
<script src="https://cdn.jsdelivr.net/npm/jtcsv/dist/jtcsv.umd.js"></script>
<script>
const csv = jtcsv.jsonToCsv([{ a: 1 }]);
</script>or as ESM module:
import { csvToJson, parseCsvFile } from 'jtcsv/browser';CLI
npx jtcsv csv-to-json data.csv --output data.json
npx jtcsv json-to-csv data.json --delimiter ";" --output out.csv
npx jtcsv csv-to-ndjson large.csv output.ndjson --stream
npx jtcsv --helpMigrating to jtcsv
# Automated codemod — rewrites imports + Papa.parse / Papa.unparse calls.
npx @jtcsv/codemod papaparse "src/**/*.{js,ts,tsx}"See @jtcsv/codemod and the manual
migration guides in docs/MIGRATION_PAPAPARSE.md and
docs/MIGRATION_CSVTOJSON.md.
Framework adapters (published)
| Package | Framework |
|------------------|---------------------------------------------------|
| @jtcsv/express | Express ^4 || ^5 |
| @jtcsv/fastify | Fastify ^4 || ^5 |
| @jtcsv/nextjs | Next.js ^13 || ^14 || ^15 |
| @jtcsv/hono | Hono ^4 |
| @jtcsv/nestjs | NestJS ^9 || ^10 || ^11 |
Client-side / meta-framework recipes (Vue, Angular, Svelte, SvelteKit,
Nuxt, Remix, tRPC) live as copy-paste examples in
examples/frameworks/ — open an issue if any
deserves a published wrapper.
Documentation
| Topic | Doc | |------------------------------|------------------------------------| | 5-minute getting started | docs/GETTING_STARTED.md | | Decision tree (which API?) | docs/API_DECISION_TREE.md | | Canonical names + aliases | docs/API_CANONICALIZATION.md | | Errors reference | docs/ERRORS.md | | Troubleshooting | docs/TROUBLESHOOTING.md | | 10 practical recipes | docs/recipes/index.md | | Schema validator | docs/SCHEMA_VALIDATOR.md | | Browser API + Web Workers | docs/BROWSER.md, docs/BROWSER_WORKERS.md | | CLI usage | docs/CLI.md | | Plugin system | docs/PLUGINS.md, docs/PLUGIN_AUTHORING.md | | Public benchmarks | docs/BENCHMARKS.md | | Migration from papaparse | docs/MIGRATION_PAPAPARSE.md | | Framework integrations | docs/integrations/ |
Status
This is a young package (created January 2026) actively pushing toward
v4.0. Public roadmap is tracked in
JTCSV_perfection_checklist.md. Real
adoption metrics live on the npm and Scorecard badges above — no
aspirational numbers are quoted in this README.
Development
npm install
npm test # full suite
npm run benchmark:vs:quick # head-to-head bench (10 K only)
npm run size # bundle-size gate
npm run tsc:check # typecheck (non-strict)
npm run tsc:check-strict:count # strict ratchet (regression gate)
npm run build # rollup + tsc declarationsReleases are managed via changesets:
npx changeset # record an intent
git push # → CI opens "Version Packages" PR
# → merge → CI publishes with --provenanceLinux validation (Docker):
docker run --rm -v /path/to/jtcsv:/work -w /work node:20 bash -lc "npm ci && npm test"License
MIT. See LICENSE.
