JSON to JSONL Converter
Paste an array or drop a .json file and get one record per line. Nesting survives, the wrapper around a paginated response is found for you, and none of it leaves your browser.
Want to trim fields or split the file first? Open the app
What refuses to take an array
A short list of systems account for almost all traffic in this direction, and each of them rejects a bracketed array with an error that does not explain itself:
- Fine-tuning uploads. Training files are one example per line by convention across every major provider. Hand the uploader an array and the validator complains about the first line rather than about the shape.
- Warehouse loaders. BigQuery's newline-delimited JSON source format, Snowflake stages, Redshift copy jobs. All of them read a line, insert a row, and move on.
- Batch and eval harnesses. Queue one job per line, write one result per line, and a run that dies halfway still leaves usable output.
- Log and event pipelines. Filebeat, Fluent Bit, Vector and friends tail a file and expect each new line to be a whole event.
- Shell tooling. Once records are lines,
head,split,shufandwc -lall work on your data without knowing any JSON at all. Sampling a thousand training examples becomes a one-liner.
The theme is appendability. An array has a closing bracket that must be the last thing in the file, so writing another record means rewriting the end of it. Lines have no such ceremony.
Worked example: an indented array of three
A product catalogue, formatted the way a repository would hold it. Note the nested stock object.
[
{
"sku": "TS-114",
"name": "Field notebook",
"price": 12.5,
"stock": { "warehouse": 240, "retail": 18 }
},
{
"sku": "TS-115",
"name": "Fountain pen",
"price": 34,
"stock": { "warehouse": 62, "retail": 9 }
},
{
"sku": "TS-116",
"name": "Ink cartridges",
"price": 6.25,
"stock": { "warehouse": 1180, "retail": 47 }
}
]
Paste that in and the output is three lines:
{"sku":"TS-114","name":"Field notebook","price":12.5,"stock":{"warehouse":240,"retail":18}}
{"sku":"TS-115","name":"Fountain pen","price":34,"stock":{"warehouse":62,"retail":9}}
{"sku":"TS-116","name":"Ink cartridges","price":6.25,"stock":{"warehouse":1180,"retail":47}}
The indentation is gone and the three records are not. stock is still an object with two keys, sitting inside its record where it always was. The result panel says 3 lines, and catalog.json downloads as catalog.jsonl. The file ends after the last record with no trailing newline, so if you plan to join two of these together, add one first or cat will glue two records into one line.
When the top level is not an array
Most of the JSON people paste here is not a bare array, because most of it came out of an API. So the engine looks for the records rather than refusing, and it always says what it assumed.
A paginated response, with the rows under a key:
{"page":1,"per_page":50,"results":[{"sku":"TS-114"},{"sku":"TS-115"}]}
Two lines come out, along with this note:
Lines were written from the "results" array. 2 other top-level fields were left out.
- One array key wins automatically. The rule is exactly one top-level key holding a non-empty array. That covers
data,items,results,recordsand whatever else the API called it, without keeping a list of blessed names. - Two array keys means no guess. A response with both
dataanderrorscould go either way, so the whole object is written as one line instead. Pick the array you want and paste that. - A lone object becomes one line. The note reads "That is one JSON object, not a list, so the output is a single line." A one-record file is a reasonable thing to want.
- Scalars are records too. Give it
[1,2,3]and you get three lines holding 1, 2 and 3. JSONL does not require objects. - JSONL in, JSONL out. Paste lines by mistake and they are read as lines, with a note saying so, then written back compactly. It doubles as a formatter.
The one thing that can be lost
Whitespace goes and nothing else does, with a single exception worth planning around: an integer written unquoted with more digits than a double can hold. Convert this
[{"order_id":12345678901234567890}]
and the line reads:
{"order_id":12345678901234567000}
The last three digits are gone, and the result says so: one number in the input is longer than JavaScript can hold exactly, so its last digits may have changed. This is not a bug in the writer. Any JSON parser built on doubles does the same, and by the time the value is in memory the original digits no longer exist anywhere. The input text is scanned for long numeric literals outside strings so you at least find out. Quoting long identifiers at the source fixes it permanently, and it is what the systems that mint them should have done.
- Key order survives. Records come out with their keys in the order the source wrote them, so a diff against another copy still means something.
- Unicode stays readable. Accented names and emoji are written as themselves, not as escape sequences.
- Near-JSON is tolerated, broken JSON is named. Single quotes, unquoted keys and trailing commas are fixed on the way in, with a note saying so. A document broken beyond that is refused with the line and column and a caret pointing at the spot; if the input looked mostly like lines, the failing line number is named instead.
- Everything runs in the tab. No upload endpoint, no account, up to 100 MB, no row cap. Beyond that the widget hands you the full editor, which streams the file.
Checking the file before you hand it over
An uploader that rejects a training file rarely tells you which record it disliked, so two minutes of checking beforehand is worth it. Once the records are lines, the checks are all ordinary shell:
- Count them.
wc -lshould report one fewer than the line count shown in the result panel, because the file has no trailing newline. If it matches the record count you expected, nothing was dropped or doubled. - Read the first one.
head -1 file.jsonland check the keys are the ones the schema names, spelled the way it spells them. - Re-parse every line.
jq -c . file.jsonlwalks the whole file and stops at the first record it cannot read, naming it. - Take a sample.
shuf -n 20 file.jsonlgives twenty random examples to read with your own eyes, which catches content problems that no validator will. - Split a large one.
split -l 50000gives you parts that are each valid JSONL, which is the property an array does not have.
Frequently Asked Questions
What is JSONL, and why would I leave a perfectly good array?
JSONL is one complete JSON value per line: no outer brackets, no commas between records, one newline as the separator. You leave the array because the array is an all-or-nothing container. Every record has to be parsed before any of it is usable, appending means rewriting the closing bracket, and a crash mid-write leaves a file no parser will touch. Lines are appendable, splittable, streamable and greppable, which is why fine-tune uploaders, warehouse loaders and log shippers ask for them.
My JSON is an object with the records under a key. Does that work?
Yes, and it says what it did. If exactly one top-level key holds a non-empty array, the lines are written from that array and the result carries a note naming the key and counting the fields it left out, such as: Lines were written from the "results" array. 2 other top-level fields were left out. That is the usual shape of a paginated API response.
What happens with a single object rather than a list?
It converts to a one-line file, with the note: That is one JSON object, not a list, so the output is a single line. Refusing would be unhelpful, because a one-record JSONL file is a perfectly valid thing to want. The same applies to a lone string, number or boolean.
Can I get the output indented?
No, and no JSONL writer should offer it. The format's one rule is that a record ends where the line ends, so an indented record would span several lines and break every reader that counts newlines. Each line here is compact JSON. If you want indentation you want a JSON array, which is the JSONL to JSON page.
Are my records changed on the way through?
Only the whitespace. Nesting stays exactly as deep as it was, arrays inside records stay arrays, key order is preserved and types are untouched. Non-ASCII text such as accented names and emoji is written as itself rather than as escape sequences. The one real exception is integers longer than JavaScript can hold, which are flagged.
Why does the result warn about long numbers?
Because the damage happened before the file reached the writer. An unquoted 20-digit id parses into a float that has already lost its last digits, and nothing downstream can recover them. The input text is scanned for long numeric literals outside strings, and if any are found the result says so and suggests quoting long ids at the source. A quoted id is safe and is the correct way to write one.
Related
Get one record per line
Paste the array or drop the .json file, check the line count, then copy the result or download the .jsonl. No sign-up and no row cap.
Back to the converter