Skip to main content

JSONL Definition

Official specification and technical standards for JSON Lines format

Formal Definition

JSON Lines (JSONL), also known as Newline Delimited JSON (NDJSON), is a text format for storing structured data. Each line consists of a valid JSON value, separated by the newline character \n (Line Feed, U+000A).

The format is designed for convenient storage and processing of structured data that may be processed one record at a time, making it ideal for streaming, logging, and append-only data scenarios.

That is the whole format: no header, no footer, no envelope, no length prefix. Because the rules are so short, most of what people believe about JSONL is convention, not specification. This page separates the two.

New to the format? The five-minute quick start walks through writing your first file. Already have one? Run it through the JSONL validator and look up whatever it reports in the parser error dictionary.

JSONL vs Standard JSON

NOT a Single Valid JSON Document

A JSONL file as a whole is not a valid JSON document. You cannot wrap the entire file in [ and ] and parse it as a JSON array.

// This is NOT valid JSON:
{"id": 1}
{"id": 2}
{"id": 3}

No Commas Between Lines

Unlike items in a JSON array, there are no commas separating the JSON objects on each line.

// JSONL - NO COMMAS:
{"name": "Alice"}
{"name": "Bob"}

// JSON Array - COMMAS REQUIRED:
[
  {"name": "Alice"},
  {"name": "Bob"}
]

No Outer Array

The entire collection of objects is not wrapped in an outer array ([ and ]). Each line stands alone.

Preserves JSON Structure

Unlike CSV, each line is a full JSON object, so it perfectly supports nested objects, arrays, and all JSON data types.

{"user": "alice", "tags": ["admin", "dev"], "meta": {"role": "lead"}}
{"user": "bob", "tags": ["user"], "meta": {"role": "member"}}

The Three Rules of the Specification

The specification at jsonlines.org states the format in exactly three rules, quoted verbatim below. Anything else is convention or advice, not conformance.

Rule 1: UTF-8 Encoding

The file must be UTF-8, with no alternative: UTF-16, Latin-1, and Shift-JIS files are not JSONL, however cleanly they parse in the tool that wrote them. UTF-8 byte sequences are self-describing, so no encoding declaration is needed.

{"name": "Müller"}
{"city": "北京"}
{"emoji": "🔥"}

Rule 2: Each Line is a Valid JSON Value

The wording rewards close reading: "any JSON value is permitted. e.g. null is a valid value but a blank line is not". Two things follow. A line is not required to be an object, and an empty line is not an empty record - it holds no JSON value, which is a parse error.

{"name": "Alice"}
["apple", "banana"]
"Hello World"
42
null

Rule 3: Line Terminator is "\n"

The terminator is Line Feed, U+000A. The specification then adds the sentence most summaries leave out: "This means '\r\n' is also supported because surrounding white space is implicitly ignored". CRLF is not a second terminator added for Windows - it works because whitespace around a value is ignored.

{"id": 1}\n
{"id": 2}\r\n
   {"id": 3}   \n

Two Rules That Are Not Actually Rules

Both claims below are repeated constantly and both are good advice. Neither is a conformance requirement, and treating them as one makes teams reject valid files.

Myth: CRLF line endings are invalid

Reality: CRLF is explicitly permitted. Rule 3 says so in as many words. A file written on Windows with \r\n terminators is valid JSONL and needs no conversion to be correct.

Preferring LF is still sound engineering: it keeps files byte-identical across platforms and sidesteps naive splitters that leave a trailing \r glued to the value. But that is a practice, not a rule.

Myth: Every line must be a JSON object

Reality: any JSON value is permitted. A line holding null, 42, "text", or [1, 2] conforms. The specification does not require records to be objects.

The convention runs the other way, and runs strongly. Object-per-line is what nearly every real file does and what libraries, log shippers, and bulk-import endpoints expect; many reject a scalar line the specification permits. So the position splits: a bare scalar line is conforming JSONL, and still a poor choice for a file you hand to other software.

// Conforming, but uncommon:
null
"a bare string record"
[1, 2, 3]

// Conventional, and what tooling expects:
{"id": 1, "value": 42}

Two Specifications, One Format

Two documents describe this format. They cover the same bytes and differ only in name, extension, and suggested media type.

JSON Lines (jsonlines.org, 2013)

Publishes the three rules above, names the format "JSON Lines", uses the .jsonl extension, and suggests application/jsonl while stating plainly that it is "not yet standardized". This is what most people mean by "the JSONL spec", and the naming this site follows.

NDJSON (GitHub specification, 2014)

A separate community specification on GitHub, naming the format "Newline Delimited JSON", using the .ndjson extension and application/x-ndjson. It arrived a year later and describes the same structure, UTF-8 requirement, and whitespace tolerance.

How the Two Relate

They are the same format. A file satisfying one satisfies the other, and nothing changes when you rename data.jsonl to data.ndjson. Only the vocabulary and recommended media type differ, which is why the MIME question below has no clean answer.

Neither went through the IETF, W3C, ECMA, or ISO. There is no working group and no version to cite; the format is stable because it is trivial, not because anyone ratified it. The history of the format covers how both names emerged, and the JSONL glossary defines the vocabulary used throughout this page.

MIME Type: What to Actually Send

One fact settles the argument: neither application/jsonl nor application/x-ndjson is registered with IANA. There is no official media type, so the question is not which is correct but which is understood.

First choice for HTTP APIs: application/x-ndjson

Content-Type: application/x-ndjson; charset=utf-8

This is the type real tooling recognises. Search engines, log pipelines, and streaming HTTP clients have converged on it, so a response labelled this way is far more likely to be handled without special configuration. The x- prefix traditionally marks an unregistered subtype.

Second choice: application/jsonl

Content-Type: application/jsonl; charset=utf-8

What jsonlines.org suggests, with the explicit caveat that the "MIME type may be application/jsonl, but this is not yet standardized". It matches the .jsonl extension, so it suits file downloads and internal services, but less third-party software recognises it.

Rare and last resort

application/jsonlines
text/x-ndjson
text/plain; charset=utf-8

The first two are unregistered and uncommon: accept them on input, do not send them. text/plain is accurate but uninformative, so use it only when nothing else is accepted. Never send application/json - a strict client will parse the whole body as one document and fail on the second line.

Always include the charset parameter

Whichever type you pick, append ; charset=utf-8. UTF-8 is mandatory for the format, but omitting the parameter leaves the decision to the recipient's default.

File Extensions

.jsonl is primary, .ndjson is equally valid and common in log and search tooling, and .jsonlines appears occasionally. Pick one per project - build scripts and editors key off the extension.

Related Standards

JSONL is not standardised itself, but it inherits two real standards and is routinely confused with a third.

RFC 8259 - JSON itself

Every line is a JSON text as defined by RFC 8259, so the whole grammar applies per line and nothing is relaxed: no comments, no trailing commas, no single-quoted strings, no unquoted keys, no NaN. It also supplies rules JSONL inherits silently - object names SHOULD be unique, numbers have no defined precision limit. A parse error is almost always RFC 8259 being violated, not a JSONL rule, and the error dictionary maps those messages back to the offending construct.

RFC 3629 - UTF-8

Rule 1 points here. RFC 3629 defines UTF-8 as the transformation format of ISO 10646, and is why a JSONL file needs no encoding declaration.

{"name": "José"}
{"location": "東京"}
{"symbol": "€"}

RFC 7464 - a different format, often confused with JSONL

RFC 7464 defines JSON Text Sequences, media type application/json-seq, and is often cited as "the standard for JSONL". It is not. It is a different wire format solving a similar problem, and the only part of this landscape that went through the IETF.

The difference is one byte with large consequences. In RFC 7464 each JSON text is preceded by an ASCII record separator, RS (0x1E), and followed by a line feed. Because that separator marks the boundary, the text between separators may contain newlines, so pretty-printed multi-line records are legal. JSONL has no separator byte and relies on the newline alone, which is why a JSONL record must sit on one line. Feed a text sequence to a JSONL parser and every line fails.

// RFC 7464 json-seq (RS shown as \x1e):
\x1e{"id": 1}\n
\x1e{"id": 2}\n

// JSONL - no separator byte:
{"id": 1}\n
{"id": 2}\n

What a Conforming Parser Must Accept

A conforming reader splits on \n, ignores whitespace around each value, parses the remainder as a JSON text, and emits one record per line in order. It must not require an outer array, objects, or a trailing newline.

Empty file: valid, zero records

A zero-byte file is conforming JSONL containing no records, and a parser that throws on it is wrong. An empty result set and a freshly rotated log both look like this.

Single line with no trailing newline: valid

The newline terminates values; it is not a required suffix on the last one. A file whose final byte is } is complete, and its last record must still be emitted. Readers that only flush on \n drop that line.

Trailing newline at end of file: valid and conventional

Ending with \n is valid and usual. It does not create a phantom empty record, and a parser must not report one. It also keeps the file appendable.

Blank line mid-file: not valid, commonly tolerated

The specification is explicit that "a blank line is not" a valid value, so one makes the file non-conforming. Most parsers skip them rather than fail, which is why the problem survives in production. Never write them, and decide deliberately whether you skip or reject.

Byte order mark: strip it

A UTF-8 BOM (U+FEFF, bytes EF BB BF) is not part of any JSON value. RFC 8259 forbids adding one and lets parsers ignore one rather than error, so a BOM makes the first line invalid JSON and whether you find out depends on your library. The symptom is unmistakable: line 1 fails, every other line is fine. Strip it on read; do not emit it.

Duplicate keys within a line: parser-defined

A JSON question, not a JSONL one. RFC 8259 says object names SHOULD be unique but does not require it, so {"id": 1, "id": 2} is not strictly invalid. Most parsers keep the last occurrence, some the first, strict modes reject the line. Never emit duplicates.

Conformance Checklist

Every item is drawn from the rules above, so a file that passes all eight conforms.

  • Encoding is UTF-8. Confirm it with a tool, not an assumption.
  • No byte order mark. The first byte of the file is the first byte of the first JSON value.
  • Every line parses as JSON on its own. Test lines independently; the file as a whole never parses.
  • No blank lines anywhere, including after the final terminator.
  • Every value sits on exactly one line. No pretty printing; escape newlines inside strings as \n.
  • No commas between lines and no outer brackets. The file is a sequence of values, not an array.
  • Line endings are LF, or CRLF. Both conform; prefer LF, uniformly.
  • Served with a deliberate media type, normally application/x-ndjson; charset=utf-8.

The JSONL validator checks the structural items in the browser.

Learn More About JSONL

Now that you understand the specification, explore advantages, compare with other formats, and see real-world examples.