Convert JSONL to a JSON array
JSONL (JSON Lines) contains one complete JSON value per line. To make a conventional JSON document from independent records, parse each line and put the values inside an array. Do not just add [ and ] around the file: array elements need commas, while JSONL lines do not.
Input, events.jsonl:
{"event":"login","userId":1}
{"event":"logout","userId":1}
Output, events.json:
[
{"event": "login", "userId": 1},
{"event": "logout", "userId": 1}
]
The JSON Lines format uses UTF-8 and requires every line to contain a valid JSON value. An empty line is not a record. Individual values need not be objects; use schema checks if your application requires objects with particular fields. See JSON vs JSONL when deciding which format fits a workflow.
Python: a small file
import json
from pathlib import Path
items = []
for number, line in enumerate(Path("events.jsonl").read_text(encoding="utf-8").splitlines(), 1):
if not line.strip():
raise ValueError(f"Blank JSONL line {number}")
try:
items.append(json.loads(line))
except json.JSONDecodeError as error:
raise ValueError(f"Invalid JSONL line {number}: {error}") from error
Path("events.json").write_text(
json.dumps(items, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
)
This loads the input and result into memory. It is convenient for a small file; it is a poor fit for gigabytes of records.
Node.js: process lines as a stream
import { createReadStream, createWriteStream } from "node:fs";
import { createInterface } from "node:readline";
const lines = createInterface({
input: createReadStream("events.jsonl", { encoding: "utf8" }),
crlfDelay: Infinity,
});
const output = createWriteStream("events.json", { encoding: "utf8" });
output.write("[\n");
let first = true;
let lineNumber = 0;
for await (const line of lines) {
lineNumber++;
if (!line.trim()) throw new Error(`Blank JSONL line ${lineNumber}`);
let value;
try {
value = JSON.parse(line);
} catch (error) {
throw new Error(`Invalid JSONL line ${lineNumber}: ${error.message}`);
}
output.write(`${first ? "" : ",\n"}${JSON.stringify(value)}`);
first = false;
}
output.end("\n]\n");
This avoids holding the whole array in memory, although it writes a partial output file if a later line is invalid. For an import pipeline, write to a temporary file and rename it only after successful completion; handle stream errors and backpressure in production code.
Validate before using the result
For a modest output, paste the completed JSON array into the JSON Validator, then use the JSON Formatter to inspect it. Those tools expect one JSON value and are not whole-file JSONL converters. For large exports, validate with your application's streaming parser instead of pasting sensitive or very large data into a browser tab.
If you get a parse error, look for a blank line, a trailing comma on a JSONL record, or a literal line break inside a quoted string. The JSON specification, RFC 8259, defines the syntax that each JSONL line must obey.