What Is JSONL (NDJSON)? The Format for Streaming JSON Data
JSON Lines and NDJSON store one JSON object per line. Learn what they are, why they beat a giant JSON array for big data, and how to convert and merge them.
If you have ever exported data from a logging platform, an ML pipeline, or a big-data tool, you may have seen a .jsonl or .ndjson file — a format that looks like JSON but with one object per line and no surrounding array. This article explains what JSON Lines is, why it exists, and how to work with it.
The format in one example
A regular JSON array of records:
[
{ "id": 1, "name": "Ada" },
{ "id": 2, "name": "Alan" },
{ "id": 3, "name": "Grace" }
]
The same data as JSONL (also called NDJSON — newline-delimited JSON):
{"id":1,"name":"Ada"}
{"id":2,"name":"Alan"}
{"id":3,"name":"Grace"}
Each line is a complete, independent JSON value. There are no enclosing brackets and no commas between lines.
Why one-object-per-line wins for big data
A single giant JSON array has a fatal flaw at scale: you must load and parse the entire file before you can use any of it, because the document is not valid until the closing ]. JSONL fixes this:
- Streamable. You can read and process one line at a time without holding the whole dataset in memory — essential for files that are gigabytes large.
- Appendable. Adding a record is just writing another line. No need to rewrite the file or fix up brackets and commas.
- Fault-tolerant. One corrupt line does not invalidate the rest of the file.
- Parallelizable. Tools can split the file by lines and process chunks concurrently.
These properties are why JSONL is the default for logs, data exports, ML training sets, and tools like BigQuery and many ETL pipelines.
Reading JSONL in code
You parse it line by line rather than all at once:
import { readFileSync } from "node:fs";
const records = readFileSync("data.jsonl", "utf8")
.split("\n")
.filter(Boolean)
.map((line) => JSON.parse(line));
In Python:
import json
with open("data.jsonl") as f:
records = [json.loads(line) for line in f if line.strip()]
Converting between JSON and JSONL
The two forms convert cleanly because JSONL is essentially a JSON array with the brackets and commas removed.
For a quick private conversion, use the JSONL to JSON converter. It validates every line and reports the exact line number for invalid records. Going the other direction, use JSON to JSONL to turn an array into newline-delimited records.
Array → JSONL:
const jsonl = array.map((o) => JSON.stringify(o)).join("\n");
JSONL → array:
const array = jsonl.split("\n").filter(Boolean).map(JSON.parse);
Merging JSONL files
Merging JSONL is often even simpler than merging JSON arrays: because each file is just a sequence of lines, concatenating the files combines the datasets:
cat part1.jsonl part2.jsonl > all.jsonl
If you need to de-duplicate records or merge objects that share an id, though, you are back to real merge logic. One clean approach: convert each JSONL file to a JSON array, merge the arrays with a merge-by-key strategy, and convert back. Our merge tool handles the array-merge step — including union and merge-by-key — so you only have to wrap the conversion around it.
JSONL vs. JSON: which to use
| JSON array | JSONL / NDJSON | |
|---|---|---|
| Whole-file validity | Required to parse | Per line |
| Memory to read | Entire file | One line |
| Appending records | Rewrite needed | Just add a line |
| Best for | Small/medium datasets, APIs | Logs, exports, big data, streaming |
Takeaway
JSONL (NDJSON) trades the tidy brackets of a JSON array for something far more practical at scale: a streamable, appendable, fault-tolerant sequence of one object per line. Use a JSON array for small payloads and APIs, and reach for JSONL whenever data gets big or needs to stream. When it comes time to combine datasets, convert to arrays and merge them with the strategy your data needs.
Ready to merge your JSON?
Combine files or snippets in your browser — free and private.
Open the merge toolKeep reading