json-2-csv
Converts arrays of JSON documents to RFC 4180 compliant CSV and back, with native support for nested sub-documents.
Repository Health
Technical Analysis
json-2-csv is a TypeScript-first Node.js library that converts arrays of JSON documents into CSV strings, and CSV strings back into JSON, while staying compliant with RFC 4180. It auto-generates the CSV header from the keys present across the provided documents, flattening nested sub-documents into dot-separated column names (e.g. specifications.mileage), and offers the reverse conversion by expanding dotted header names back into nested objects.
Beyond the basic conversion, the library exposes a large set of options for controlling exactly how data round-trips: custom field/wrap/EOL delimiters, schema-difference checking across documents, key selection (including wildcard-prefix matching and human-readable title remapping), array unwinding into one CSV row per value, expansion of arrays of objects, Excel-safe byte-order-mark prepending, CSV-injection prevention, and custom value parsers for both directions.
The core package is intentionally minimal in its own dependency footprint - it relies on two small companion libraries by the same author (doc-path for reading/writing dotted paths and deeks for deep key discovery) rather than pulling in a general utility library, and ships full TypeScript typings alongside a synchronous API surface introduced in v5. A separate CLI package (@mrodrig/json-2-csv-cli) wraps the library for command-line json2csv/csv2json usage, keeping the core library’s footprint small for programmatic consumers.
What You Get
- Two focused async functions,
json2csvandcsv2json, each accepting a rich but fully optional options object with sensible RFC 4180-compliant defaults - Automatic header/key detection across a document array via the companion
deekslibrary, including configurable handling of array indexes and nested object expansion - Bidirectional dotted-path handling for nested documents (
doc-path), so{a: {b: 1}}round-trips through thea.bCSV column and back - Fine-grained conversion controls: custom delimiters, key selection with wildcard matching and title remapping, array unwinding/expansion, trimming, sorting headers, and custom value parsers
- Full TypeScript type definitions shipped with the package, plus a synchronous usage path alongside the default async/Promise-based API
Common Use Cases
- Exporting arrays of API or database query results (including nested sub-documents) to a downloadable CSV file for end users or reporting pipelines
- Importing user-uploaded CSV files (e.g. bulk data imports) back into structured JSON documents for validation and persistence
- Building CLI-driven ETL scripts that convert JSON logs or exports into CSV for spreadsheet analysis, via the companion
@mrodrig/json-2-csv-clipackage - Normalizing CSV field values (dates, locale-formatted numbers, boolean wrapping) so exported files open correctly in Excel and other spreadsheet tools
Under The Hood
Architecture
The package’s public surface (src/converter.ts) is a thin dispatcher: json2csv/csv2json build a normalized options object via buildJ2COptions/buildC2JOptions in src/utils.ts, validate the input shape, and hand off to factory functions Json2Csv/Csv2Json that each return a closure-scoped convert(). Inside src/json2csv.ts, conversion is a clear, single-direction pipeline threaded through a shared params object - retrieveHeaderFields -> unwindRecordsIfNecessary -> processRecords -> wrapHeaderFields -> trimHeaderFields -> generateCsvHeader -> generateCsvFromComponents - with each stage a small, named function rather than one large procedure, and cross-cutting helpers (path evaluation, unwind, empty-field checks) factored out into src/utils.ts and the doc-path/deeks dependencies. The design favors composability of options over inheritance or class hierarchies; nothing here would break under a change to a “core abstraction” beyond the shared params shape both directions rely on.
Tech Stack
Written entirely in TypeScript (98%+ of the codebase) targeting Node 16+, compiled via tsc against a dedicated tsconfig.build.json. Runtime dependencies are deliberately minimal - just doc-path and deeks, both maintained by the same author - avoiding a general-purpose utility library. Linting uses ESLint with the eslint-config-google base plus the TypeScript ESLint plugin; tests run under Mocha with ts-node/register, coverage via nyc with check-coverage enforced and reported to Coveralls. GitHub Actions runs the lint/test/coverage matrix across Node 20, 22, and 24. The CLI functionality has been deliberately extracted into a separate @mrodrig/json-2-csv-cli package, keeping the library’s own dependency surface small for programmatic consumers.
Code Quality
The test suite is extensive: dedicated files for json2csv, csv2json, and shared utilities are backed by dozens of paired JSON/CSV fixture files under test/data/ covering edge cases such as excluded keys, wildcard matching, Excel BOM handling, CSV injection prevention, unwind/expand combinations, locale formatting, and malformed/empty input. Coverage is measured with nyc and gated (check-coverage: true) rather than merely reported, and CI enforces linting and multi-version Node compatibility on every push. Error paths use explicit, centrally defined error messages (src/constants.ts) rather than swallowing failures, and the public API is fully typed end-to-end.
API Design
The library commits to exactly two entry points with an options object rather than a sprawling method surface, which keeps the common case (json2csv(data), csv2json(csv)) a one-line call while still exposing deep control for advanced cases (wildcard key matching with title remapping, custom parseValue hooks, unwind vs. expand semantics for arrays). Defaults are chosen for RFC 4180 correctness out of the box, and the README documents every option with runnable before/after examples, lowering the cost of discovering advanced behavior. The problem domain itself - JSON/CSV interconversion - is a well-trodden one, so the design is best described as unusually thorough and well-documented within a standard pattern rather than conceptually novel.
Used by 8 apps in this directory
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Laminar
AI Development · Monitoring
Open-source observability platform purpose-built for AI agents — trace, evaluate, debug, and monitor at scale with SQL access and real-time replay.
medusa
Ecommerce
The most flexible open-source commerce platform — build B2C, B2B, and marketplace applications with modular, composable commerce primitives.
OpenObserve
Monitoring · Analytics · Devops
Open source observability platform for logs, metrics, traces, and real user monitoring — delivering 140x lower storage costs than Elasticsearch with a single binary you can run in under 2 minutes.
Rocket.Chat
Team Chat
The secure, self-hosted team communications platform for organizations that cannot compromise on data sovereignty.
Sanity
CMS
Open-source headless CMS with a fully customizable React Studio, real-time collaborative editing, structured content modeling, and GROQ query language
twenty
CRM
The open-source CRM you build, ship, and version like the rest of your stack — with customizable objects, AI agents, and a TypeScript SDK.
Unleash
Developer Tools · Devops · Ab Testing Experimentation
The open-source feature management platform that lets you ship code to production and control who sees it — without redeploying.