JSON Streaming

JSON streaming is a technique for processing large amounts of JSON data piece by piece, without loading the entire dataset into memory at once. Standard JSON parsing waits for the full document before doing anything. Streaming JSON processing starts working on the data as it arrives.

Why JSON Streaming Is Important

Imagine a truck delivering 10,000 boxes to a warehouse. One approach: the truck unloads all 10,000 boxes into the parking lot, then workers carry them into the warehouse one by one. Another approach: workers start carrying boxes inside as soon as the truck begins unloading. The second approach is faster and uses less parking lot space.

JSON streaming works the same way. Instead of loading a 500 MB JSON file completely into memory before processing, you process each record as it comes in. This keeps memory usage low and allows you to start producing results immediately.

When Standard JSON Parsing Fails

Standard JSON.parse() workflow:
--------------------------------
[Read ENTIRE file into memory]
            |
            v
[Parse ENTIRE string into object]
            |
            v
[Process the data]

Problem: A 500 MB JSON file requires 500 MB+ of RAM just to load
         before you can do anything with it.

Types of JSON Streaming

1. Newline-Delimited JSON (NDJSON)

NDJSON is the most common streaming format. Each line is a complete, valid JSON object. There is no outer array wrapping everything. Each line is independent.

NDJSON File Example (logs.ndjson)

{"timestamp":"2026-09-01T08:00:01Z","level":"INFO","message":"Server started"}
{"timestamp":"2026-09-01T08:00:05Z","level":"INFO","message":"User 42 logged in"}
{"timestamp":"2026-09-01T08:01:12Z","level":"WARN","message":"High memory usage"}
{"timestamp":"2026-09-01T08:02:45Z","level":"ERROR","message":"DB connection failed"}
{"timestamp":"2026-09-01T08:02:50Z","level":"INFO","message":"DB reconnected"}

Each line is a self-contained JSON object. You can process them one by one, stop at any line, or start from any line. This format is used for log files, data exports, and real-time event streams.

2. JSON Lines (JSONL)

JSONL is essentially the same as NDJSON. The file extension is .jsonl. Each line is one JSON value. It is popular in machine learning for training datasets because you can easily shuffle lines or process a subset.

3. Streaming Array (Chunked)

Some APIs stream a JSON array by sending chunks. The response starts with [, sends each item one by one, and ends with ]. The client processes each item as it arrives without waiting for the closing bracket.

Diagram: Standard vs Streaming JSON Processing

STANDARD JSON (Load All First)
--------------------------------
Server sends all data
    ↓
Client stores 500 MB in RAM
    ↓
Parse complete document
    ↓
Start processing record 1
    ↓
Process record 2...
    ↓
Process record 500,000

STREAMING JSON (Process As It Arrives)
---------------------------------------
Server sends record 1
    ↓                ← Process record 1 immediately
Server sends record 2
    ↓                ← Process record 2
...continues...
    ↓
Server sends record 500,000
    ↓                ← Process record 500,000

RAM usage: Only 1 record at a time instead of 500,000

Reading NDJSON in Node.js

Line-by-Line Processing with readline

const fs = require('fs');
const readline = require('readline');

const fileStream = fs.createReadStream('./logs.ndjson');

const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity  // Handle Windows line endings
});

let errorCount = 0;

rl.on('line', (line) => {
  // Each line is a complete JSON object
  if (line.trim() === '') return; // Skip empty lines

  const logEntry = JSON.parse(line);

  if (logEntry.level === 'ERROR') {
    errorCount++;
    console.log('Error found:', logEntry.message);
  }
});

rl.on('close', () => {
  console.log(`Total errors found: ${errorCount}`);
  console.log('Processing complete.');
});

Writing NDJSON in Node.js

const fs = require('fs');

const logs = [
  { timestamp: "2026-09-01T08:00:01Z", level: "INFO", message: "Server started" },
  { timestamp: "2026-09-01T08:00:05Z", level: "INFO", message: "User logged in" },
  { timestamp: "2026-09-01T08:02:45Z", level: "ERROR", message: "DB failed" }
];

// Write each object as one line
const writer = fs.createWriteStream('./output.ndjson');

logs.forEach(log => {
  writer.write(JSON.stringify(log) + '\n');
});

writer.end(() => {
  console.log('NDJSON file written successfully');
});

Reading NDJSON in Python

error_count = 0

with open('logs.ndjson', 'r', encoding='utf-8') as file:
    for line in file:
        line = line.strip()
        if not line:
            continue  # Skip empty lines

        log_entry = json.loads(line)  # Parse one line at a time

        if log_entry['level'] == 'ERROR':
            error_count += 1
            print('Error:', log_entry['message'])

print(f'Total errors: {error_count}')

Python processes one line at a time from the file. The entire 500 MB file never loads into memory.

Streaming JSON from an HTTP API in Node.js

When an API streams data, you process each chunk as it arrives instead of buffering everything.

const https = require('https');

let buffer = '';

https.get('https://api.example.com/events/stream', (response) => {

  response.on('data', (chunk) => {
    buffer += chunk.toString();

    // Process complete lines from the buffer
    const lines = buffer.split('\n');
    buffer = lines.pop(); // Keep any incomplete last line in buffer

    lines.forEach(line => {
      if (line.trim()) {
        const event = JSON.parse(line);
        console.log('Received event:', event.type, event.data);
      }
    });
  });

  response.on('end', () => {
    console.log('Stream ended');
  });
});

Server-Sent Events (SSE) with JSON

Server-Sent Events is a browser standard for receiving real-time updates from a server. Each event typically contains JSON data. This is how live sports scores, chat messages, and notifications work.

Server (Node.js with Express)

const express = require('express');
const app = express();

app.get('/scores', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  // Send a score update every 3 seconds
  const interval = setInterval(() => {
    const scoreUpdate = {
      team: "India",
      score: Math.floor(Math.random() * 300),
      wickets: Math.floor(Math.random() * 10),
      timestamp: new Date().toISOString()
    };

    res.write(`data: ${JSON.stringify(scoreUpdate)}\n\n`);
  }, 3000);

  // Clean up when client disconnects
  req.on('close', () => {
    clearInterval(interval);
    res.end();
  });
});

app.listen(3000);

Browser Client

const eventSource = new EventSource('/scores');

eventSource.onmessage = (event) => {
  const scoreUpdate = JSON.parse(event.data);
  document.getElementById('score').textContent =
    `${scoreUpdate.team}: ${scoreUpdate.score}/${scoreUpdate.wickets}`;
};

eventSource.onerror = () => {
  console.log('Connection error or stream ended');
};

Real-World Use Cases for JSON Streaming

  • Log processing — Parse millions of log lines without loading everything into RAM.
  • Data export tools — Export database tables as NDJSON for transfer or backup.
  • Machine learning datasets — JSONL files store training data line by line for easy shuffling.
  • Live chat and notifications — SSE streams JSON events to the browser in real time.
  • Large API responses — Stream a list of 100,000 products without waiting for all 100,000 before showing any.
  • Financial data feeds — Stream stock ticks or trade events as they happen.

NDJSON vs JSON Array

Feature              NDJSON                     JSON Array
-------              ------                     ----------
Can stream           Yes - process line by line  No - need full array first
File size limit      No practical limit           Limited by available RAM
Append new items     Just add a new line          Must re-parse the whole file
Validate one item    Parse just that line         Must parse entire array
Shuffle/split data   Easy - rearrange lines       Complex without full parse

Summary

JSON streaming processes data piece by piece instead of loading everything at once. Newline-Delimited JSON (NDJSON) and JSON Lines (JSONL) store one JSON object per line, making them easy to stream and process in any order. Node.js and Python both have built-in tools to process NDJSON line by line with minimal memory usage. Server-Sent Events stream JSON events from server to browser in real time. Use streaming whenever your JSON dataset is too large to load into memory all at once, or when you need real-time data delivery.

Leave a Comment

Your email address will not be published. Required fields are marked *