JSONL

Parse newline-delimited JSON (JSONL) with Bun's built-in streaming parser

Bun has built-in support for parsing JSONL (newline-delimited JSON), where each line is a separate JSON value. The parser is implemented in C++ using JavaScriptCore's optimized JSON parser and supports streaming.

const results = Bun.JSONL.parse('{"name":"Alice"}\n{"name":"Bob"}\n');
// [{ name: "Alice" }, { name: "Bob" }]

Bun.JSONL.parse()#

Parse a complete JSONL input and return an array of all parsed values.

import { JSONL } from "bun";

const input = '{"id":1,"name":"Alice"}\n{"id":2,"name":"Bob"}\n{"id":3,"name":"Charlie"}\n';
const records = JSONL.parse(input);
console.log(records);
// [
//   { id: 1, name: "Alice" },
//   { id: 2, name: "Bob" },
//   { id: 3, name: "Charlie" }
// ]

Input can be a string or a Uint8Array:

const buffer = new TextEncoder().encode('{"a":1}\n{"b":2}\n');
const results = Bun.JSONL.parse(buffer);
// [{ a: 1 }, { b: 2 }]

With Uint8Array input, Bun skips a UTF-8 BOM at the start of the buffer.

Error handling#

If the input contains invalid JSON and no values were successfully parsed, Bun.JSONL.parse() throws a SyntaxError. If at least one value was parsed before the error, it returns the parsed values without throwing.

try {
  Bun.JSONL.parse("{invalid}\n");
} catch (error) {
  console.error(error); // SyntaxError: Failed to parse JSONL
}

Bun.JSONL.parseChunk()#

For streaming, parseChunk parses as many complete values as it can from the input and reports how far it got. That way you know where to resume when data arrives incrementally (for example, from a network stream).

const chunk = '{"id":1}\n{"id":2}\n{"id":3';

const result = Bun.JSONL.parseChunk(chunk);
console.log(result.values); // [{ id: 1 }, { id: 2 }]
console.log(result.read); // 17 — characters consumed
console.log(result.done); // false — incomplete value remains
console.log(result.error); // null — no parse error

Return value#

parseChunk returns an object with four properties:

PropertyTypeDescription
valuesany[]Array of successfully parsed JSON values
readnumberNumber of bytes (for Uint8Array) or characters (for strings) consumed
donebooleantrue if the entire input was consumed with no remaining data
errorSyntaxError | nullParse error, or null if no error occurred

Streaming example#

Use read to slice off consumed input and carry forward the remainder:

let buffer = "";

async function processStream(stream: ReadableStream<string>) {
  for await (const chunk of stream) {
    buffer += chunk;
    const result = Bun.JSONL.parseChunk(buffer);

    for (const value of result.values) {
      handleRecord(value);
    }

    // Keep only the unconsumed portion
    buffer = buffer.slice(result.read);
  }

  // Handle any remaining data
  if (buffer.length > 0) {
    const final = Bun.JSONL