JSON Lines (also called JSONL, or NDJSON, “Newline Delimited JSON”) is a variation of the JSON format designed specifically for handling multiple records, one per line, instead of a single giant document. It’s not a completely different format from JSON, it’s more of a specific convention for organizing several JSON documents together.
The problem JSONL solves
If you’ve ever tried to represent a list of records in plain JSON, you probably used an array.
// json
[
{"name": "Ana", "age": 30},
{"name": "John", "age": 25},
{"name": "Maria", "age": 28}
]
This works fine for small lists. But in scenarios with millions of records (application logs, database data exports, streaming events), a single giant JSON array has some practical problems:
- To read the entire array, many parsing libraries need to load the whole document into memory first, even if you only want to process one record at a time
- If the file gets interrupted midway (for example, a process that crashes while generating it), the entire JSON becomes invalid, since the array’s closing bracket is missing
- Adding a new record at the end requires reopening and rewriting the whole structure (removing the
], adding a comma, adding the new item, closing it again)
How JSONL solves this
Instead of an array, each line of the file is an independent, complete JSON document, separated by a line break.
// jsonl
{"name": "Ana", "age": 30}
{"name": "John", "age": 25}
{"name": "Maria", "age": 28}
Notice there’s no comma between records, no brackets wrapping everything. Each line is, on its own, valid JSON by itself.
Practical advantages
Line-by-line processing (streaming): you can read and process one record at a time, without loading the entire file into memory.
# python
import json
with open("data.jsonl", "r") as file:
for line in file:
record = json.loads(line)
print(record["name"])
This is especially useful for very large files, where loading everything at once would use too much memory.
Resilience to interruptions: if the process generating the file gets interrupted midway, the lines already written remain individually valid JSON. You only lose the record that was being written at the moment of the interruption, not the whole file.
Easy to append: adding a new record is just writing a new line at the end of the file, with no need to reread or rewrite anything that already existed.
# python
with open("data.jsonl", "a") as file:
new_record = {"name": "Carlos", "age": 40}
file.write(json.dumps(new_record) + "\n")
Where JSONL is used in practice
- Application logs: many structured logging tools (like Elasticsearch/Logstash) natively work with one JSON record per line
- Machine learning datasets: it’s common to see large datasets distributed as
.jsonl, since ML frameworks tend to process data in a stream, record by record - Database data exports: exporting a large table as JSONL is more practical than generating a single giant JSON array
- Streaming APIs: some APIs return responses as a stream of JSONL, where each line arrives as it becomes available, instead of waiting for the complete response
Common mistake: treating JSONL as regular JSON
If you try to use JSON.parse() (or the equivalent) on the entire content of a JSONL file at once, you’ll get an error like “unexpected non-whitespace character after JSON” (already covered in another post on the blog), because technically it’s several valid JSON documents, one after another, with nothing tying them into a single structure.
// javascript
// Wrong
JSON.parse(jsonlFileContent); // error
// Right
const records = jsonlFileContent
.split('\n')
.filter(line => line.trim() !== '')
.map(line => JSON.parse(line));
Quick checklist
- Confirmed the file format is actually JSONL (one line per record) and not a regular JSON array?
- Processing the file line by line, instead of trying to load everything into memory at once?
- When generating JSONL, made sure each line is a complete, valid JSON on its own, with no internal line breaks in the middle of a record?
- Remembered to filter out empty lines before parsing (files often have a blank line at the end)?
If you need to validate a single line from a JSONL file, paste it into JSON Validator to confirm it’s correct.