npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nanocsv

v0.2.0

Published

Tiny, zero-dependency, correct CSV parser & stringifier — quotes, escaped quotes, embedded commas/newlines, optional type coercion (numbers/booleans/null), and a CSV↔JSON CLI. ~1KB, works in Node, Deno, Bun & the browser.

Readme

nanocsv

A tiny, correct CSV parser & stringifier in ~1 KB. Zero dependencies. Handles the quoting edge cases naive split-on-comma code gets wrong.

npm version bundle size CI types license

"a,b".split(",") breaks the moment a value contains a comma, a quote, or a newline. nanocsv parses CSV the right way — a proper RFC 4180 state machine — in two functions and about a kilobyte.

import { parse, stringify } from "nanocsv";

parse('id,name\n1,"Doe, John"');          // [["id","name"],["1","Doe, John"]]
parse("id,name\n1,Ada", { header: true }); // [{ id: "1", name: "Ada" }]

stringify([{ id: 1, name: "Doe, John" }]); // 'id,name\n1,"Doe, John"'

Why nanocsv?

  • 🪶 Zero dependencies, ~1 KB gzipped. No papaparse-sized download for a simple job.
  • Actually correct. Quoted fields, escaped quotes (""), embedded commas and newlines, \n and \r\n.
  • 🔁 Round-trips. parse and stringify are designed to be lossless together.
  • 🧩 Two functions. Strings in, strings/objects out. No streams to wire up, no config object to memorize.
  • 🌍 Runs everywhere. Node 18+, Deno, Bun, Cloudflare Workers and the browser.
  • 🛡️ Type-safe. Written in TypeScript; header: true changes the return type to objects.

Install

npm install nanocsv
# or: pnpm add nanocsv  /  yarn add nanocsv  /  bun add nanocsv

Ships ESM and CommonJS:

import { parse, stringify } from "nanocsv";        // ESM / TypeScript
const { parse, stringify } = require("nanocsv");   // CommonJS

CLI

Convert between CSV and JSON without installing anything:

npx nanocsv to-json data.csv --typed --pretty   # CSV → typed JSON
cat data.json | npx nanocsv to-csv              # JSON array → CSV
npx nanocsv format data.csv --out-delimiter ";" # change the delimiter

Commands: to-json, to-csv, format. Options: -d/--delimiter, --out-delimiter, --no-header, --typed, --pretty. Reads a file or stdin, writes stdout.

Usage

Parsing

// Matrix of strings (default)
parse("a,b,c\n1,2,3");
// → [["a","b","c"], ["1","2","3"]]

// Objects keyed by the header row
parse("name,age\nAda,36\nBob,40", { header: true });
// → [{ name: "Ada", age: "36" }, { name: "Bob", age: "40" }]

// Coerce numbers / booleans / null — quoted fields stay strings
parse("name,age,active\nAda,36,true", { header: true, dynamicTyping: true });
// → [{ name: "Ada", age: 36, active: true }]
parse('id\n"007"', { dynamicTyping: true }); // → [["id"], ["007"]]  (quoted ⇒ string)

// Quotes, embedded commas and newlines just work
parse('x,"a,b","line1\nline2"');
// → [["x", "a,b", "line1\nline2"]]

// Other formats
parse("a;b;c", { delimiter: ";" });   // semicolons
parse("a\tb\tc", { delimiter: "\t" }); // TSV
parse(" a , b ", { trim: true });      // trim each field
parse("# header\na,b", { comment: "#" }); // skip comment lines

Stringifying

// From rows
stringify([["a", "b"], [1, 2]]);
// → "a,b\n1,2"

// From objects (header inferred from keys)
stringify([{ a: 1, b: 2 }, { a: 3, b: 4 }]);
// → "a,b\n1,2\n3,4"

// Fix the column order, or drop the header
stringify(records, { header: ["id", "name", "email"] });
stringify(records, { header: false });

// Only fields that need quoting are quoted
stringify([["plain", "needs,quote", 'has "quote"']]);
// → 'plain,"needs,quote","has ""quote"""'

// Or quote everything, and pick your line ending
stringify(rows, { quoteAll: true, newline: "\r\n", delimiter: ";" });

API

parse(input, options?)

Returns string[][], or Record<string, string>[] when header: true.

| Option | Type | Default | Description | | ---------------- | --------- | ------- | ------------------------------------------------- | | delimiter | string | "," | Field separator. | | quote | string | '"' | Quote character. | | header | boolean | false | Use the first row as keys and return objects. | | skipEmptyLines | boolean | true | Drop blank lines. | | trim | boolean | false | Trim whitespace around each field. | | comment | string | — | Skip lines starting with this (outside quotes). |

stringify(rows, options?)

Accepts an array of arrays or an array of plain objects. Returns a string.

| Option | Type | Default | Description | | ----------- | --------------------- | ------- | -------------------------------------------------------------- | | delimiter | string | "," | Field separator. | | quote | string | '"' | Quote character. | | newline | string | "\n" | Record separator. | | header | boolean \| string[] | true* | Emit/define the header. *Default true for objects only. | | quoteAll | boolean | false | Quote every field instead of only when required. |

Values are coerced with String(); null/undefined become empty fields and plain objects are JSON-stringified.

Comparison

| | nanocsv | "x".split(",") | papaparse | | ---------------------------- | :-------: | :--------------: | :---------: | | Quoted fields / commas | ✅ | ❌ | ✅ | | Escaped quotes & newlines | ✅ | ❌ | ✅ | | Parse and stringify | ✅ | ❌ | ✅ | | Zero dependencies | ✅ | ✅ | ✅ | | ~1 KB gzipped | ✅ | ✅ | ❌ |

Need streaming gigabyte files or worker threads? Reach for papaparse. Need to correctly parse the CSV you actually have, in a kilobyte? That's nanocsv.

Contributing

Contributions are very welcome! Please read CONTRIBUTING.md and our Code of Conduct.

git clone https://github.com/didrod205/nanocsv.git
cd nanocsv
npm install
npm test

💖 Sponsor

nanocsv is free and MIT-licensed, built and maintained in spare time. If it saved you from debugging a broken CSV split, please consider supporting it — every bit helps keep the project healthy.

  • Star this repo — the simplest, free way to help others discover it.
  • 🍋 Sponsor via Lemon Squeezy — one-time or recurring support.

Sponsoring? Open an issue and we'll add your name/logo here. Thank you! 🙏

License

MIT © nanocsv contributors