Skip to content

Examples

Short, copy-paste recipes for the common tasks, each linking to the full guide. Runnable versions live in the examples/ directory and are type-checked in CI, so they stay in sync with the library.

The encoding recipes build on this shared setup:

ts
import { createCsvEncoder, parse, stringify, toReadableStream } from 'csv-pipe';

type User = { name: string; email: string; age: number };

const users: User[] = [
  { name: 'Alex Johnson', email: 'alex@example.com', age: 29 },
  { name: 'Carlos Herrera', email: 'carlos@example.com', age: 24 }
];

Encode an array of objects

The header is inferred from the record keys, and a field is quoted only when it needs to be.

ts
stringify(users);
// name,email,age
// Alex Johnson,alex@example.com,29
// Carlos Herrera,carlos@example.com,24

Parse CSV into typed records

parse is the mirror of stringify. See Parsing.

ts
parse<User>('name,email,age\nAlex Johnson,alex@example.com,29');
// [{ name: 'Alex Johnson', email: 'alex@example.com', age: '29' }]

Select, order, and rename columns

A map sets the header label per key. See Choosing columns.

ts
stringify(users, { columns: { name: 'Full name', email: 'Email address' } });
// Full name,Email address
// Alex Johnson,alex@example.com
// Carlos Herrera,carlos@example.com

Format dates and numbers

A Date becomes an ISO string on its own; the format hook handles the rest. See Formatting values.

ts
type Order = { id: number; total: number; placedAt: Date };

const orders: Order[] = [
  { id: 1, total: 19.5, placedAt: new Date('2026-06-04T10:00:00Z') }
];

stringify(orders, {
  format: (value) => (typeof value === 'number' ? value.toFixed(2) : value)
});
// id,total,placedAt
// 1.00,19.50,2026-06-04T10:00:00.000Z

Serve a CSV over HTTP

toReadableStream turns the encoder into a response body with no buffering. See Streaming.

ts
const encoder = createCsvEncoder<User>({ columns: ['name', 'email'] });

function handler(): Response {
  return new Response(toReadableStream(encoder.stream(users)), {
    headers: { 'content-type': 'text/csv; charset=utf-8' }
  });
}

Write a large file in Node

writeCsv streams the encoder straight to a file. See Streaming.

ts
import { writeCsv } from 'csv-pipe/node';

await writeCsv('users.csv', users, { columns: ['name', 'email'] });

Read a large file in Node

readCsv parses a file as a stream of records, so it is never fully loaded. See Streaming and files.

ts
import { readCsv } from 'csv-pipe/node';

for await (const user of readCsv<User>('users.csv')) {
  // one record at a time
}

Validate each row

The row hook receives each record and returns the final element, so a schema or a guard enforces the type. See Typing and validation.

ts
parse('id\n1\n2', { row: (record) => ({ id: Number(record.id) }) });
// [{ id: 1 }, { id: 2 }]

Guard untrusted exports

sanitizeFormulas prefixes any cell that a spreadsheet might read as a formula. See Security.

ts
const exportRows = [
  { name: '=1+1', note: 'leading equals' },
  { name: '@SUM(A1:A9)', note: 'leading at' }
];

stringify(exportRows, { sanitizeFormulas: true });
// name,note
// '=1+1,leading equals
// '@SUM(A1:A9),leading at

Download in the browser

downloadCsv encodes the data and triggers a download. See Streaming.

ts
import { downloadCsv } from 'csv-pipe/browser';

downloadCsv(users, { filename: 'users.csv' });

Runnable examples

Run any of these with a TypeScript runner, for example npx tsx examples/basic.ts.

ExampleShows
basic.tsEncode an array of objects into a CSV string.
columns.tsSelect, order, and label columns.
formatting.tsTransform values with the format hook.
streaming-node.tsStream to a file with flat memory.
streaming-web.tsServe a CSV as an HTTP response.
read-file.tsParse a file as a stream of typed records.
security.tsGuard against formula injection.

Released under the MIT License.