JSONL, also called JSON Lines or NDJSON, is a text format where each line is its own JSON value. For logs, AI training data, large-scale imports and exports, and streaming, JSONL is often a better fit than normal JSON.
Normal JSON is excellent for a complete object, config file, or API response. JSONL is closer to an appendable stream of records. It still uses JSON syntax, but the file is not one large array; it is a sequence of independent JSON lines.
Basic JSONL rules
- Each line is one complete JSON record, usually an object.
- Every line should be parseable on its own; there are no commas between lines.
- A trailing newline at the end of the file is fine, and readers usually process the file line by line.
- Do not pretty-print one object across multiple lines inside a JSONL file, because that breaks the one-record-per-line contract.
A JSONL example
{"timestamp":"2026-09-21T10:00:00Z","level":"info","message":"job started","jobId":"import-42"}
{"timestamp":"2026-09-21T10:00:02Z","level":"warn","message":"retrying row","row":128}
{"timestamp":"2026-09-21T10:00:05Z","level":"info","message":"job finished","records":1000000}The three lines above are three separate records. A program can read the first line, append a fourth line, or resume from the middle without parsing the entire file into memory.
How is JSONL different from a JSON array?
[
{
"timestamp": "2026-09-21T10:00:00Z",
"level": "info",
"message": "job started",
"jobId": "import-42"
},
{
"timestamp": "2026-09-21T10:00:02Z",
"level": "warn",
"message": "retrying row",
"row": 128
}
]| Aspect | Normal JSON | JSONL |
|---|---|---|
| File structure | Usually one object or array | Many independent JSON records |
| Appending data | You must preserve commas and the closing bracket | Append one new line |
| Reading model | Often parsed as a whole file | Can be read and processed line by line |
| Error impact | One syntax error can break the whole file | Usually only the bad line fails |
| Best scale | Small to medium configs, API responses, document data | Logs, events, training samples, batch imports and exports |
Why logs are a natural fit for JSONL
Logs are produced one event at a time. If you store them as a normal JSON array, the writer has to keep managing commas, the closing bracket, and file completeness. With JSONL, each log event is serialized as one line and appended.
That also makes downstream processing easier: command-line tools, log collectors, queue consumers, and warehouse loaders can consume records line by line without waiting for the file to finish.
Why AI training data often uses JSONL
AI training and fine-tuning datasets often contain many independent examples. Each example can be validated, filtered, shuffled, split, or labeled on its own. JSONL matches that sample-level workflow.
{"messages":[{"role":"user","content":"Summarize this log entry"},{"role":"assistant","content":"The import job started successfully."}],"source":"logs"}
{"messages":[{"role":"user","content":"Classify the ticket urgency"},{"role":"assistant","content":"high"}],"source":"support"}In this structure, one line is one training example. Data teams can run schema checks, deduplicate, sample, and quality-review individual lines, then merge many JSONL files into a larger dataset.
Common use cases
- Logs: application logs, audit logs, analytics events, and system metric snapshots.
- AI training data: conversation examples, classification samples, instruction-tuning data, and labeling records.
- Large imports and exports: database dumps, search index rebuilds, and data warehouse batch loads.
- Streaming: queue consumers, real-time ETL, long-running responses, and chunked downloads.
- Data cleanup pipelines: filtering, mapping, aggregation, and sampling without loading the entire file at once.
When should you still use normal JSON?
If your data is one hierarchical document, such as a config file, UI state snapshot, single API response, or payload that must be handled as one transaction, normal JSON is clearer. JSONL is strongest when you have many independent records.
Summary
JSONL turns a large dataset into independently processable records. It gives up the single-document feel of a JSON array, but gains easier appends, line-by-line reading, better error isolation, and streaming-friendly processing.