Drop a JSON Lines file. Any size.
safe · secure · no server · works offline · fast
…or just start typing at the cursor.
safe · secure · no server · works offline · fast
…or just start typing at the cursor.
OmniViewer opens a JSON Lines file right in your browser. Drop a
.jsonl or .ndjson file and you get a
record browser with every record validated, an inferred
schema, and one-click conversion to CSV or a
JSON array. There is no upload and no server — the file
is read directly by your browser, and the scan runs in a background Web
Worker so the page never freezes.
JSON Lines is one complete JSON value per line — the format
every log pipeline, analytics export, LLM fine-tuning set and
BigQuery/Athena/DuckDB dump uses. That is also why
JSON.parse(file) fails on it and why most JSON viewers show you
an error instead of your data: the file is not one document, it is millions of
them.
user.plan and array‑element items[].sku), how many records carry it, the percentage of records it appears in, every type it was seen with, and an example value. It also names the fields whose type drifts between records.
This is what the route is for. A JSONL export is produced by a pipeline and
consumed by a loader, and when the loader stops it says something like
invalid JSON on line 12,000,412 — with no way to look at line
12,000,412. OmniViewer reads every byte of the file, however
large, and reports each broken record with its record number, its byte offset
and the parse error, then opens it on one click. The three failures it finds
most often are a truncated final line (a killed process, a lost multipart
upload), a trailing comma left over from thinking in arrays, and a
pretty‑printed JSON document saved with a .jsonl extension
— which the viewer detects by name rather than reporting 400,000
identical errors.
.jsonl file
JSON Lines is the one JSON dialect where a record boundary is a
byte, not a parser state: a record ends at the next newline, and
0x0A cannot appear inside a UTF‑8 multi‑byte sequence
or inside a JSON string. So the whole file can be split with a plain byte
scan, in 4 MB blocks, carrying only the partial trailing record across a
block edge — peak memory is one block plus the field table, whatever the
file weighs. That is why the record count, the broken‑record list and
the schema cover the entire file rather than a sample. The two conversions
(CSV and JSON array) have to produce one document, so they work on a bounded
prefix and say so. For the full story with real code, read
what is a .jsonl file? JSON Lines and NDJSON explained.
The format has no single inventor and no RFC — it was reinvented
independently wherever someone needed to put JSON in a pipe, which is why it
has four names for the same bytes: JSON Lines
(.jsonl, the spelling of jsonlines.org and the common one today),
NDJSON (“newline‑delimited JSON”, the name
the streaming ecosystem uses), LDJSON
(“line‑delimited”, older, from logging stacks) and loosely
“JSON stream”. Its rise came with big‑data tooling in the
2010s: Hadoop, Spark, Athena and BigQuery all want to hand byte range
k of a file to worker k, and only a line‑delimited
format lets them find a record boundary without a parser. MIME types you will
meet are application/x-ndjson and
application/jsonl; neither is registered with IANA. Do not
confuse any of it with JSON Text Sequences (RFC 7464), which
separates records with a 0x1E byte instead of a newline.
A tiny example of JSON Lines:
{"id":1,"name":"Ada","tags":["admin"]}
{"id":2,"name":"Bob"}
{"id":3,"name":"Cy","tags":[]}
| Aspect | JSON Lines | JSON | CSV | Parquet |
|---|---|---|---|---|
| Shape | One value per line | One nested document | Flat rows | Columnar, binary |
| Nested data | Yes, per record | Yes | No | Yes |
| Schema | None — implicit, per record | None | Header row, untyped | Typed, in the footer |
| Appendable | Yes, one line at a time | No | Yes | No |
| Split without parsing | Yes, at any newline | No | Usually | By row group |
| Streaming read memory | One record | Whole document | One row | One column chunk |
| Survives truncation | Yes — lose the last record | No | Yes | No |
| Typical use | Logs, exports, training sets | APIs & config | Spreadsheets | Analytics storage |
OmniViewer opens every file format; JSON Lines is one of the formats with dedicated tooling, alongside JSON, CSV and Parquet — powered by the same viewing engine as fastjsonviewer.com and hugecsv.com.
No. OmniViewer is a static page with no server-side processing: your .jsonl or .ndjson file is read directly by your browser, and every tab — records, schema, CSV, JSON and stats — runs locally in a Web Worker. The file never leaves your computer.
A .jsonl file is JSON Lines: one complete JSON value per line, separated by newlines, with no wrapping array and no commas between records. A .json file is a single document. That is why JSON.parse on a whole .jsonl file fails at the start of the second record — it finished a complete value and then found more content. Each individual line, however, is perfectly valid JSON.
Yes. JSON Lines (.jsonl), NDJSON (newline-delimited JSON, .ndjson) and LDJSON (line-delimited JSON, .ldjson) all describe the same bytes: one JSON value per line. OmniViewer treats them as one toolkit, so a .ndjson file opens on the same route with the same tabs. JSON Text Sequences (RFC 7464) is genuinely different — it separates records with a 0x1E byte, not a newline.
Effectively unlimited, up to 20 GB and beyond; the engine behind the raw and hex views has been tested in-browser with a 40 GB file. The record scan is the same: because a record boundary in JSON Lines is a single newline byte, the whole file is streamed in 4 MB blocks and only the partial trailing record is carried across a block edge, so the record count, the broken-record list and the schema cover every byte. The CSV and JSON-array conversions produce one document, so those work on a bounded prefix and tell you when they do.
Yes — that is the point of the route. Every record in the file is parsed, and each one that fails is listed with its record number, the byte offset it starts at and the parse error, wherever it sits in the file. Click it to open the record itself. If the whole file turns out to be a pretty-printed JSON document saved with a .jsonl extension, the viewer says so by name instead of reporting one error per line.
Yes, both. The CSV tab flattens each record to one row, turning nested objects into dotted column names and keeping arrays as JSON in a single cell; columns are the union of every record’s fields, so a record missing one gets an empty cell. The JSON tab wraps the records into one pretty-printed JSON array. Both are ready to copy or download, and both work on a bounded prefix of a very large file and say so.
JSON Lines has no schema, so nothing in the file guarantees that every record has the same fields or the same types. The schema tab walks every record and reports each field path with the share of records that carry it and the mix of types it was seen with. That is where you discover that user.email is in a quarter of your records, or that qty is a number in most of them and a string in a few — the reason a strict load into BigQuery, a typed struct or a Parquet writer rejects an export that parsed perfectly.
Yes. A trailing carriage return is whitespace as far as JSON is concerned, so CRLF files read the same as LF ones. Blank lines are not records: they are skipped and counted separately in stats. A UTF-8 byte-order mark is treated as belonging to the file rather than to the first record, so it never turns record 1 into a parse error.