NDJSON and JSON Lines explained
A log file or an export can hold millions of records. Store them as one giant JSON array and any reader has to load the whole thing into memory and wait for the final closing bracket before a single record is valid. NDJSON, also called JSON Lines, fixes that by putting one complete JSON value on each line.
What it looks like
Each line is an independent JSON document, ended by a newline. There are no enclosing brackets and no commas between records.
{"ts":"2026-10-01T10:00:00Z","level":"info","msg":"started"}
{"ts":"2026-10-01T10:00:01Z","level":"warn","msg":"slow query"}
{"ts":"2026-10-01T10:00:02Z","level":"error","msg":"timeout"}
The file as a whole is not valid JSON. Each line, read on its own, is.
Why one object per line wins
The design pays off anywhere data arrives or is read incrementally:
- Streaming. A consumer can parse and act on each line the moment it arrives, without waiting for the end of the stream.
- Appending. Adding a record is a single write of one more line. With a wrapping array you would have to seek to the end, remove the closing bracket, add a comma, and rewrite it.
- Fault tolerance. One corrupt line does not poison the rest. You skip it and keep going. A broken array fails to parse entirely.
- Line tools.
grep,wc -l,head, andtailwork directly, because records line up with lines.
This is why NDJSON is the common format for application logs, database exports, and APIs that return large result sets.
How to read it
Process it one line at a time rather than parsing the file as a unit:
for (const line of text.split("\n")) {
if (!line.trim()) continue; // skip blank lines
const record = JSON.parse(line);
handle(record);
}
The two things that trip people up: ignore empty lines, especially a trailing newline at the end of the file, and do not try to run the whole file through JSON.parse at once. If you need to inspect a single noisy record, copy that one line out and paste it into the JSON Formatter to pretty print it. The input never leaves your browser, so pasting a line from a production log is safe even when it carries user data.
Converting to and from an array
Turning NDJSON into a normal array is a join; going the other way is a map. Keep the direction clear in your head:
- NDJSON to array: split on newlines, parse each line, collect into one array.
- Array to NDJSON: map each element through
JSON.stringifyand join with newlines.
The takeaway: use NDJSON whenever records are produced or consumed over time, like logs and streams, and reserve a single JSON array for small, complete payloads you hold in memory all at once. When a record misbehaves, format that one line, not the whole file.