NDJSON Complete Guide: Newline Delimited JSON Explained

A comprehensive guide to Newline Delimited JSON (NDJSON). Learn the specification, MIME type, how to read and write NDJSON in Python, Node.js, and the command line, use it in streaming HTTP APIs, and understand its relationship with JSONL.

Last updated: February 2026

What Is NDJSON?

NDJSON stands for Newline Delimited JSON. It is a text-based data format where each line contains exactly one valid JSON value, separated by a newline character (\n). The format was designed for streaming and processing large datasets without loading the entire file into memory. Unlike a standard JSON file that wraps everything in a single array or object, NDJSON lets you read, write, and process records one at a time.

The NDJSON specification is hosted at github.com/ndjson/ndjson-spec. It was created to formalize a pattern that had already become common in log shipping, data pipelines, and HTTP streaming APIs. Each line is self-contained: if one line contains invalid JSON, other lines can still be parsed successfully. This makes NDJSON fault-tolerant and well-suited for append-only workflows such as application logs, event streams, and incremental data exports.

NDJSON Example (3 records)
{"id":1,"event":"page_view","url":"/home"}
{"id":2,"event":"click","url":"/pricing"}
{"id":3,"event":"signup","url":"/register"}

The NDJSON Specification

The official NDJSON specification at github.com/ndjson/ndjson-spec is intentionally minimal. It defines a simple convention for serializing multiple JSON values in a single text stream. The core rules are straightforward:

The specification explicitly avoids adding headers, metadata, or schema information to the format. This keeps NDJSON as simple as possible and compatible with standard Unix text processing tools. Any valid JSON value is allowed on each line, though in practice most NDJSON files contain JSON objects with a consistent set of keys.

  • Each line MUST contain exactly one valid JSON value (object, array, string, number, boolean, or null).
  • Lines are separated by the newline character '\n' (U+000A). The carriage return '\r' (U+000D) may appear before '\n' but is not required.
  • A trailing newline after the last JSON value is allowed but not required.
  • Each JSON value must not contain unescaped newline characters within the value itself.

Because the rules are minimal, NDJSON is easy to generate from any programming language that has a JSON serializer. Simply serialize each record, append a newline, and write it to the output. No closing brackets, no trailing commas, no enclosing array structure to worry about.

NDJSON vs JSON vs JSONL

NDJSON, JSON, and JSONL each have a different structure. Standard JSON encodes a single value (usually an array or object). JSONL and NDJSON both store one JSON value per line, and they are functionally identical to each other. The table below highlights the key differences between all three formats.

FeatureJSONJSONLNDJSON
Full NameJavaScript Object NotationJSON LinesNewline Delimited JSON
File Extension.json.jsonl.ndjson
MIME Typeapplication/jsonapplication/jsonl (unofficial)application/x-ndjson
SpecificationRFC 8259 (IETF standard)jsonlines.org (community)github.com/ndjson/ndjson-spec (community)
Line DelimiterN/A (single value)\n (newline)\n (newline)
Trailing NewlineN/ARecommendedOptional
Stream-FriendlyNo (must parse entire document)Yes (line-by-line)Yes (line-by-line)

NDJSON MIME Type: application/x-ndjson

The registered MIME type for NDJSON is application/x-ndjson. This content type is used in HTTP headers to indicate that the response body contains newline-delimited JSON data. Many streaming APIs, including the GitHub API, Docker Registry API, and Elasticsearch bulk API, use this MIME type to deliver NDJSON responses.

HTTP Content-Type Header
Content-Type: application/x-ndjson
# Example: curl a streaming API
curl -H "Accept: application/x-ndjson" https://api.example.com/events/stream
# Example: Express.js response
res.setHeader('Content-Type', 'application/x-ndjson');
res.write(JSON.stringify(record) + '\n');

Some APIs also accept application/json-seq (RFC 7464) or text/plain as alternatives. However, application/x-ndjson is the most widely adopted MIME type for newline-delimited JSON streams. When building a new API that streams JSON records, use application/x-ndjson for maximum compatibility.

Reading and Writing NDJSON

Working with NDJSON is straightforward in any language that supports JSON. Below are practical examples for Python, Node.js, and the command line.

Python's built-in json module handles NDJSON naturally. Read lines from a file, parse each one with json.loads, and write with json.dumps. For large files, this line-by-line approach uses constant memory.

Python: Read and Write NDJSON
guide-ndjson-complete-guide.ndjsonGuide.readWrite.python.code

In Node.js, use the readline module with fs.createReadStream to parse NDJSON files efficiently. The stream processes one line at a time, keeping memory usage low regardless of file size.

Node.js: Read and Write NDJSON
import { createReadStream, writeFileSync } from 'node:fs';
import { createInterface } from 'node:readline';
// Read NDJSON
async function readNdjson(filePath) {
const records = [];
const rl = createInterface({
input: createReadStream(filePath, 'utf-8'),
crlfDelay: Infinity,
});
for await (const line of rl) {
const trimmed = line.trim();
if (trimmed) records.push(JSON.parse(trimmed));
}
return records;
}
// Write NDJSON
const data = [
{ id: 1, event: 'page_view' },
{ id: 2, event: 'click' },
];
const ndjson = data.map(r => JSON.stringify(r)).join('\n') + '\n';
writeFileSync('output.ndjson', ndjson, 'utf-8');

The jq command-line tool natively understands NDJSON input. Use the --slurp flag to collect all records into an array, or process each record individually without any flag.

Command Line: Process NDJSON with jq
# Print each record (jq reads NDJSON by default)
jq '.' data.ndjson
# Filter records where event is "click"
jq 'select(.event == "click")' data.ndjson
# Extract specific fields
jq {id, url} data.ndjson
# Count total records
jq -s 'length' data.ndjson
# Convert NDJSON to a JSON array
jq -s '.' data.ndjson > data.json
# Convert a JSON array back to NDJSON
jq -c '.[]' data.json > data.ndjson

NDJSON in HTTP Streaming APIs

NDJSON is the de facto standard for HTTP streaming APIs that deliver real-time data. When a server sends an NDJSON response, the client can begin processing the first record as soon as it arrives, without waiting for the entire response to complete. This is faster and more memory-efficient than returning a large JSON array.

Popular services that use NDJSON streaming include Docker Registry (image layer events), Elasticsearch (bulk operations), Apache CouchDB (changes feed), and many modern event-driven APIs. The pattern works well with Server-Sent Events alternatives, real-time log tailing, and progressive data loading in web applications.

Express.js NDJSON Streaming Server
import express from 'express';
const app = express();
app.get('/api/events/stream', (req, res) => {
res.setHeader('Content-Type', 'application/x-ndjson');
res.setHeader('Transfer-Encoding', 'chunked');
// Simulate streaming events
let id = 0;
const interval = setInterval(() => {
id++;
const event = {
id,
type: 'heartbeat',
timestamp: new Date().toISOString(),
};
res.write(JSON.stringify(event) + '\n');
if (id >= 100) {
clearInterval(interval);
res.end();
}
}, 100);
req.on('close', () => clearInterval(interval));
});
app.listen(3000);
Browser: Consume NDJSON Stream with Fetch
async function* readNdjsonStream(url) {
const response = await fetch(url, {
headers: { 'Accept': 'application/x-ndjson' },
});
const reader = response.body
.pipeThrough(new TextDecoderStream())
.getReader();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += value;
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (line.trim()) yield JSON.parse(line);
}
}
if (buffer.trim()) yield JSON.parse(buffer);
}
// Usage
for await (const event of readNdjsonStream('/api/events/stream')) {
console.log('Received:', event);
}

NDJSON Ecosystem Tools

A growing ecosystem of command-line tools and libraries supports NDJSON natively. These tools let you filter, transform, and analyze NDJSON data without writing custom code.

jq

Essential

jq is the most popular command-line JSON processor. It reads NDJSON by default (one JSON value per line) and supports filtering, mapping, grouping, and reformatting. Use jq -c for compact output and jq -s to slurp all records into an array.

ndjson-cli

CLI

ndjson-cli is a collection of Unix-style commands for manipulating NDJSON streams: ndjson-filter, ndjson-map, ndjson-reduce, ndjson-sort, and ndjson-join. Each command reads from stdin and writes to stdout, making them composable with pipes.

ndjson (npm)

Node.js

The ndjson npm package provides streaming NDJSON parsers and serializers for Node.js. It exposes ndjson.parse() and ndjson.stringify() transform streams that integrate directly into Node.js stream pipelines for high-throughput data processing.

NDJSON and JSONL: Interoperability

NDJSON and JSONL (JSON Lines) are functionally identical formats. Both store one JSON value per line, separated by newline characters. A file that is valid NDJSON is also valid JSONL, and vice versa. You can rename a .ndjson file to .jsonl (or the other way around) without changing a single byte of content, and every tool that reads one format will read the other.

The only differences are cosmetic: NDJSON comes from github.com/ndjson/ndjson-spec and uses the .ndjson extension with the application/x-ndjson MIME type, while JSONL comes from jsonlines.org and uses the .jsonl extension. In practice, most developers treat the two names as synonyms. If your project already uses JSONL, there is no need to migrate to NDJSON, and if a library says it supports NDJSON, it will work with your .jsonl files without any changes.

JSONL vs NDJSON: Detailed Comparison

For a deeper dive into the history, specification differences, and community adoption of JSONL and NDJSON, read our dedicated comparison guide.

Try Our Free NDJSON/JSONL Tools

Work with NDJSON and JSONL files right in your browser. All processing happens locally, so your data stays private.

Work with NDJSON Files Online

View, validate, and convert NDJSON and JSONL files up to 1 GB right in your browser. No uploads required, 100% private.

Frequently Asked Questions

NDJSON Format Guide β€” Newline Delimited JSON & JSONL Expl...