How to Parse NDJSON Streams Using Axios
Newline Delimited JSON (NDJSON) delivers individual JSON objects
separated by newline characters (\n), making it ideal for
streaming large or real-time datasets. Because Axios attempts to parse
entire HTTP responses as a single JSON object by default, standard
configurations will throw a syntax error when encountering NDJSON. The
recommended approach to parse NDJSON with Axios is to set the
responseType to 'stream' in Node.js (or read
the response body as a stream) and process the incoming chunks
line-by-line using a stream splitter or the native readline
module.
Why Standard Axios Fails with NDJSON
Axios automatically invokes JSON.parse() on response
data when the server returns a JSON content type. Because NDJSON
contains multiple adjacent JSON strings that are not wrapped in an
array, standard parsing fails immediately. To process NDJSON
successfully, you must:
- Disable automatic JSON transformation.
- Consume the HTTP response body as a stream.
- Buffer and split chunks on newline characters
(
\n). - Parse each line independently with
JSON.parse().
Recommended
Node.js Implementation: Using readline
The cleanest native approach in Node.js uses the built-in
readline module. It automatically buffers incoming chunks,
identifies line breaks, and emits individual lines for parsing.
const axios = require('axios');
const readline = require('readline');
async function streamNDJSON(url) {
try {
const response = await axios({
method: 'get',
url: url,
responseType: 'stream' // Tells Axios to return a Node.js Readable Stream
});
const rl = readline.createInterface({
input: response.data,
crlfDelay: Infinity // Recognizes all instances of CR LF (\r\n) as a single line break
});
rl.on('line', (line) => {
const trimmed = line.trim();
if (!trimmed) return; // Skip empty lines
try {
const jsonRecord = JSON.parse(trimmed);
console.log('Parsed record:', jsonRecord);
} catch (err) {
console.error('Failed to parse line:', line, err.message);
}
});
rl.on('close', () => {
console.log('NDJSON stream finished.');
});
response.data.on('error', (err) => {
console.error('Stream error:', err);
});
} catch (error) {
console.error('Axios request failed:', error.message);
}
}
streamNDJSON('https://example.com/data.ndjson');Alternative
Node.js Implementation: Using split2
For pipeline-based stream processing, the split2 library
transforms raw byte streams into streams of individual lines that can be
piped into a transform or writable stream.
npm install split2 through2const axios = require('axios');
const split2 = require('split2');
const through2 = require('through2');
async function fetchWithPipeline(url) {
const response = await axios({
method: 'get',
url: url,
responseType: 'stream'
});
response.data
.pipe(split2()) // Splits stream on \n
.pipe(through2.obj((line, enc, cb) => {
if (line.trim()) {
try {
const parsed = JSON.parse(line);
// Process record
console.log(parsed);
} catch (e) {
return cb(e);
}
}
cb();
}))
.on('error', (err) => console.error('Pipeline error:', err))
.on('finish', () => console.log('Processing complete.'));
}Handling NDJSON in the Browser
In browser environments, Axios uses XMLHttpRequest by
default, which does not support Node.js streams. To stream NDJSON in the
browser using Axios, enable the fetch adapter (available in
Axios v1.x+) and read the ReadableStreamDefaultReader:
import axios from 'axios';
async function streamBrowserNDJSON(url) {
const response = await axios.get(url, {
responseType: 'stream',
adapter: 'fetch' // Requires Axios v1.7+ for native Fetch adapter
});
const reader = response.data.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
// Retain incomplete last line in buffer
buffer = lines.pop();
for (const line of lines) {
if (line.trim()) {
const record = JSON.parse(line);
console.log('Record:', record);
}
}
}
// Parse any remaining content in the buffer
if (buffer.trim()) {
console.log('Final Record:', JSON.parse(buffer));
}
}Best Practices
- Always Wrap
JSON.parseintry...catch: A single malformed line or network anomaly should not crash your entire streaming process. - Ignore Empty Lines: NDJSON streams often end with
or contain empty newline characters; always verify
line.trim()has content before parsing. - Clean Up Stream Listeners: In Node.js, ensure
stream error listeners are attached directly to
response.datato prevent unhandled stream errors.