What is difference between json and ndjson?

Modern software systems constantly exchange data.

A frontend application communicates with a backend API. Microservices exchange messages. Applications generate logs. Data pipelines process millions of records. AI systems consume datasets. Cloud services export events.

Behind many of these interactions is one of the most common data formats in software development: JSON.

But when the amount of data becomes large or needs to be processed as a stream, traditional JSON can become inconvenient. This is where NDJSON — Newline Delimited JSON — becomes useful.

Although JSON and NDJSON look very similar, they solve slightly different problems.

Understanding the difference can help software engineers make better decisions when designing APIs, logging systems, data pipelines, bulk-processing jobs, streaming systems, and distributed applications.


What Is JSON?

JSON stands for JavaScript Object Notation.

JSON is a lightweight, text-based format used to represent and exchange structured data. Despite its JavaScript-inspired name, JSON is language-independent and is supported by practically every mainstream programming language.

The current JSON Internet Standard is defined by RFC 8259. It describes JSON as a lightweight, text-based, language-independent data interchange format derived from ECMAScript.

A simple JSON document might look like this:

{
"id": 1001,
"name": "Alice",
"email": "alice@example.com",
"active": true
}

JSON supports a small number of fundamental data types:

  • String
  • Number
  • Boolean
  • Null
  • Object
  • Array

For example:

{
"application": "OrderService",
"version": "2.1",
"enabled": true,
"retryCount": 3,
"servers": [
"server-01",
"server-02"
],
"database": {
"type": "PostgreSQL",
"port": 5432
}
}

This simplicity is one of the main reasons JSON became so popular.


A Brief History of JSON

JSON grew out of the object-literal syntax used by JavaScript.

As web applications became increasingly interactive, developers needed a convenient way for browsers and servers to exchange structured information.

Earlier web applications frequently relied on XML.

For example:

<user>
<id>1001</id>
<name>Alice</name>
<active>true</active>
</user>

The equivalent JSON representation is considerably more compact:

{
"id": 1001,
"name": "Alice",
"active": true
}

JSON eventually became popular because it was simple to generate, relatively easy for humans to read, and easy for programming languages to parse.

Douglas Crockford authored RFC 4627 in 2006, which formally described JSON and registered the application/json media type. Later specifications refined the format, including RFC 7159 in 2014 and the current RFC 8259 published in December 2017.

JSON is also defined by ECMA-404. The first edition of ECMA-404 was published in October 2013, with the second edition published in December 2017.

Today JSON is deeply embedded in software development.

It is commonly used for:

  • REST APIs
  • Web applications
  • Mobile applications
  • Configuration files
  • Microservice communication
  • Database documents
  • Cloud APIs
  • Event messages
  • Application metadata
  • Infrastructure tools

Why Do We Need JSON?

Imagine a Java application communicating with a JavaScript frontend.

Internally, Java may represent a customer as:

Customer customer = new Customer(
1001,
"Alice",
"alice@example.com"
);

JavaScript might represent the same information differently.

Python may use a dictionary.

C# may use a class.

Go may use a struct.

The systems therefore need a common representation that can travel across a network.

JSON provides that representation.

The Java backend can serialize an object into JSON:

{
"id": 1001,
"name": "Alice",
"email": "alice@example.com"
}

The receiving application can then deserialize the JSON into its own internal object model.

JSON therefore acts as a common language between applications.


Benefits of JSON

1. Human Readable

JSON is relatively easy for humans to inspect.

{
"status": "success",
"orderId": 9821
}

Developers can quickly understand what the message represents.


2. Language Independent

JSON is not limited to JavaScript.

Libraries for parsing and generating JSON exist in almost every commonly used programming language, including:

  • Java
  • Python
  • JavaScript
  • TypeScript
  • C#
  • Go
  • Rust
  • PHP
  • Ruby
  • Kotlin

3. Excellent API Support

JSON has effectively become the default representation for many web APIs.

For example:

GET /api/customers/1001

might return:

{
"id": 1001,
"name": "Alice",
"status": "ACTIVE"
}

4. Supports Nested Data

JSON can naturally represent hierarchical information.

{
"orderId": 1001,
"customer": {
"id": 55,
"name": "Alice"
},
"items": [
{
"product": "Laptop",
"quantity": 1
},
{
"product": "Mouse",
"quantity": 2
}
]
}

This makes JSON especially useful for REST APIs and domain objects.


5. Easy Serialization and Deserialization

Frameworks generally provide excellent JSON support.

For example, Spring Boot applications commonly use Jackson to convert Java objects into JSON.

@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}

Spring can automatically serialize the returned object into JSON.


Disadvantages of JSON

JSON is extremely useful, but it is not ideal for every situation.

Large JSON Documents

Suppose an application needs to return one million records.

A traditional JSON response might look like:

[
{"id":1,"name":"Alice"},
{"id":2,"name":"Bob"},
{"id":3,"name":"Carol"}
]

The array may continue for millions of records.

Some applications may attempt to load the complete document into memory before processing it.

For very large datasets, this can become expensive.


Difficult Partial Processing

Traditional JSON often represents a complete document.

A parser frequently expects the structure to be complete before processing finishes.

If a huge JSON document is interrupted halfway through transmission, the entire JSON document may be invalid.


Appending Data Is Awkward

Consider a JSON log file:

[
{"time":"10:00","message":"Application started"},
{"time":"10:01","message":"User logged in"}
]

Adding another event requires maintaining the surrounding array structure and commas correctly.

For continuously generated information such as logs or events, this is inconvenient.

This problem leads us to NDJSON.


What Is NDJSON?

NDJSON stands for:

Newline Delimited JSON

Instead of putting multiple records inside one JSON array, NDJSON stores each JSON value on its own line.

For example:

{"id":1,"name":"Alice"}
{"id":2,"name":"Bob"}
{"id":3,"name":"Carol"}
{"id":4,"name":"David"}

Each line is an independent JSON record.

The NDJSON specification describes the format specifically as a way of delimiting JSON texts in stream protocols. The specification was created in July 2013, with version 1.0.0 updated in October 2014.

The specification requires each JSON text to be followed by a newline and requires UTF-8 encoding.

You may also encounter the term:

JSON Lines

or files using:

.jsonl

JSON Lines follows essentially the same record-per-line idea and is commonly described as newline-delimited JSON.

You will therefore commonly encounter extensions such as:

events.ndjson

or:

events.jsonl

JSON vs. NDJSON

The easiest way to understand the difference is through an example.

Traditional JSON:

[
{
"id": 1,
"name": "Alice"
},
{
"id": 2,
"name": "Bob"
},
{
"id": 3,
"name": "Carol"
}
]

NDJSON:

{"id":1,"name":"Alice"}
{"id":2,"name":"Bob"}
{"id":3,"name":"Carol"}

They represent similar information but organize it differently.

With JSON, the entire collection is one JSON array.

With NDJSON, each line is its own JSON value.

This creates an important difference:

An entire NDJSON file is generally not one valid JSON document.

Instead, it is a sequence of valid JSON records separated by newline characters.


JSON vs. NDJSON Comparison

FeatureJSONNDJSON
StructureSingle JSON documentMultiple JSON records
Record separatorJSON syntaxNewline
Typical extension.json.ndjson or .jsonl
REST API responsesExcellentUseful for streaming APIs
Small datasetsExcellentUsually unnecessary
Very large datasetsCan become difficultExcellent
StreamingPossible, but less convenientExcellent
Append operationsAwkwardEasy
Log filesPossibleExcellent
Human readabilityVery goodVery good
Process one record at a timeMore difficultEasy
Parallel processingLess convenientEasier
Nested structuresExcellentExcellent within each record

Why Do We Need NDJSON?

NDJSON addresses an important limitation of regular JSON:

What if we don’t want to process the entire document at once?

Consider a dataset containing 50 million transactions.

Traditional JSON might look like:

[
{...},
{...},
{...},
{...}
]

An application may need to process the overall document structure while reading it.

With NDJSON:

{...}
{...}
{...}
{...}

the application can simply:

  1. Read one line.
  2. Parse the JSON.
  3. Process the record.
  4. Release it from memory.
  5. Read the next line.

Memory usage can therefore remain relatively stable even when processing extremely large datasets.

This is one of NDJSON’s biggest advantages.


Benefits of NDJSON

1. Streaming

NDJSON works extremely well for streaming data.

Imagine receiving events continuously:

{"event":"LOGIN","userId":101}
{"event":"SEARCH","userId":101}
{"event":"PURCHASE","userId":101}

The consumer does not need to wait for the entire dataset.

It can process each event immediately.

The NDJSON specification explicitly identifies streaming protocols such as TCP and UNIX pipes as important use cases.


2. Lower Memory Requirements

Suppose a 20 GB dataset contains millions of JSON records.

Loading everything into memory may be impossible.

NDJSON allows:

Read line
↓
Parse JSON
↓
Process
↓
Discard
↓
Read next line

Only a small portion of the dataset needs to exist in memory at any particular time.


3. Easy to Append

Imagine an application producing logs.

With NDJSON, another record can simply be added:

{"timestamp":"10:00","level":"INFO","message":"Application started"}
{"timestamp":"10:01","level":"INFO","message":"Database connected"}
{"timestamp":"10:02","level":"ERROR","message":"Request failed"}

No closing array bracket needs to be rewritten.


4. Better Fault Isolation

Suppose one record is malformed:

{"id":1,"name":"Alice"}
{"id":2,"name":"Bob"}
INVALID
{"id":4,"name":"David"}

Depending on the application’s error-handling strategy, it may be possible to reject the invalid line while continuing to process subsequent records.

With one enormous JSON document, syntax corruption can potentially invalidate the entire document.


5. Unix Command-Line Friendly

Because each record occupies one line, NDJSON works naturally with command-line processing.

For example:

grep '"status":"ERROR"' application.ndjson

or:

head -100 application.ndjson

or:

wc -l application.ndjson

This can make debugging and operational analysis very convenient.

JSON Lines documentation specifically highlights compatibility with Unix-style text-processing tools and shell pipelines.


Disadvantages of NDJSON

NDJSON also has limitations.

It Is Not a Single JSON Document

You cannot necessarily pass an entire NDJSON file directly to a normal JSON parser.

For example:

{"id":1}
{"id":2}

A parser expecting one JSON document may fail because two objects appear sequentially.

Instead, the application normally reads and parses the data line by line.


Relationships Between Records Are Less Explicit

Consider:

{
"customers": [
{...},
{...}
],
"metadata": {
"total": 200
}
}

JSON naturally represents relationships between the collection and its metadata.

NDJSON usually treats each line as an independent record.

You may need additional conventions for headers, metadata, totals, schemas, or summaries.


Not Every Tool Supports NDJSON

Nearly every modern programming language understands JSON.

NDJSON support is less universal.

Applications may need custom line-reading logic or libraries designed for streaming JSON records.


Multiline Formatting Is Not Practical

Pretty-printed JSON is easy to read:

{
"id": 1,
"name": "Alice"
}

NDJSON records normally remain on one physical line:

{"id":1,"name":"Alice"}

This is important because the newline separates records.

The NDJSON specification requires JSON texts themselves not to contain literal newline or carriage-return delimiters outside their JSON string escaping.


When Should We Use JSON?

Use traditional JSON when you are dealing with a relatively small, complete data structure.

Typical examples include:

REST API Responses

{
"userId": 100,
"username": "alice",
"roles": ["USER", "ADMIN"]
}

Configuration Files

{
"database": "PostgreSQL",
"timeout": 30,
"retry": 3
}

Application Settings

{
"theme": "dark",
"notifications": true
}

Structured Domain Objects

JSON is excellent when relationships and nested structures matter.

{
"orderId": 1001,
"customer": {...},
"items": [...],
"shippingAddress": {...}
}

A useful rule is:

If the consumer needs the complete structure as one document, JSON is usually the better choice.


When Should We Use NDJSON?

Consider NDJSON when records can be processed independently.

Typical scenarios include:

  • Large datasets
  • Streaming APIs
  • Application logs
  • Event streams
  • Data exports
  • ETL pipelines
  • Machine learning datasets
  • AI training data
  • Bulk database operations
  • Analytics pipelines
  • Message processing
  • Command-line processing

A useful rule is:

If records naturally arrive or can be processed one at a time, NDJSON may be the better choice.


Use Case 1: Application Logging

Suppose a microservice produces structured logs.

Instead of:

2026-08-08 10:00 User login successful

we could produce:

{"timestamp":"2026-08-08T10:00:00Z","service":"authentication","level":"INFO","userId":123,"event":"LOGIN_SUCCESS"}

The next event becomes another line:

{"timestamp":"2026-08-08T10:00:01Z","service":"authentication","level":"INFO","userId":456,"event":"LOGIN_SUCCESS"}

NDJSON is a natural format for structured logging because events are generated independently and continuously.


Use Case 2: Processing Millions of Database Records

Suppose we export 20 million customers.

Traditional JSON:

[
{...},
{...},
{...}
]

NDJSON:

{...}
{...}
{...}

A processing application can read each customer independently.

This is extremely useful for ETL workflows:

Database
↓
Export NDJSON
↓
Streaming Processor
↓
Transform Record
↓
Load Into Data Warehouse

Use Case 3: Streaming APIs

Suppose an API performs a search that may return 500,000 records.

Instead of waiting until all records are collected:

Client
↓
Request
↓
Server processes 500,000 records
↓
Server creates huge JSON document
↓
Response

an NDJSON-based endpoint can stream results:

Client
↓
Request
↓
Record 1
↓
Record 2
↓
Record 3
↓
...

The client can begin processing results before the server has finished generating the complete result set.


Use Case 4: AI and Machine Learning Datasets

NDJSON and JSON Lines are particularly useful when datasets contain many independent examples.

For example:

{"input":"What is REST?","output":"REST is an architectural style..."}
{"input":"What is JSON?","output":"JSON is a data interchange format..."}
{"input":"What is OAuth?","output":"OAuth is an authorization framework..."}

Each training or evaluation example can be processed independently.

This structure is convenient for:

  • LLM datasets
  • Model evaluations
  • Data preprocessing
  • Batch processing
  • Embedding generation
  • Data transformation

Use Case 5: Event-Driven Systems

Consider an e-commerce platform generating events:

{"type":"ORDER_CREATED","orderId":101}
{"type":"PAYMENT_COMPLETED","orderId":101}
{"type":"ORDER_SHIPPED","orderId":101}

These are naturally independent events.

NDJSON can therefore be useful for exporting, replaying, debugging, or archiving event streams.

It does not replace technologies such as Kafka, RabbitMQ, or ActiveMQ, but it can be a convenient serialization and storage format around event-processing systems.


Using JSON and NDJSON Together

JSON and NDJSON should not necessarily be considered competitors.

A modern system may use both.

For example:

Browser
|
| JSON
↓
REST API
|
| JSON
↓
Business Services
|
| Events
↓
Message Broker
|
| NDJSON export
↓
Analytics Pipeline
|
↓
Data Warehouse

The important question is not:

Should our organization use JSON or NDJSON?

Instead ask:

Which representation is appropriate for this particular data flow?


JSON vs. NDJSON in Microservices

For normal synchronous microservice communication, JSON is usually appropriate.

For example:

Order Service
|
| JSON REST API
↓
Payment Service

But suppose we need to export five million orders.

Creating an endpoint such as:

GET /api/orders

that returns:

[
millions of records
]

may be inefficient.

Instead, a streaming endpoint might return NDJSON:

GET /api/orders/export

Response:

{"orderId":1,"amount":100}
{"orderId":2,"amount":250}
{"orderId":3,"amount":85}

The normal transactional API still uses JSON while the bulk export uses NDJSON.


How Can We Integrate JSON and NDJSON Decisions Into Our Software Development Process?

Understanding JSON and NDJSON should influence architecture and API design instead of being treated merely as a file-format decision.

1. Define Data Characteristics During API Design

When designing an API, ask:

  • How many records could this endpoint return?
  • Can records be processed independently?
  • Does the client need the entire result?
  • Could the dataset eventually contain millions of records?
  • Does the client need results immediately?
  • Will the response be streamed?

Small structured response:

Use JSON.

Large independent record stream:

Consider NDJSON.


2. Avoid Unlimited JSON Responses

Developers should be suspicious of endpoints such as:

GET /api/customers/all

If there are 100 customers today, returning an array is easy.

What happens when there are 10 million customers?

Options should include:

  • Pagination
  • Cursor-based pagination
  • Streaming
  • Asynchronous exports
  • NDJSON
  • Compressed bulk files

This decision should be made during API architecture reviews.


3. Use Structured Logging

Instead of plain text:

Payment failed for user 123

consider structured records:

{
"timestamp": "2026-08-08T14:30:00Z",
"level": "ERROR",
"service": "payment-service",
"userId": 123,
"event": "PAYMENT_FAILED"
}

When logs are continuously written, representing each event as a JSON object on one line creates an NDJSON-like structured log.

Log-management systems can then query fields such as:

level
service
userId
event
timestamp

instead of attempting to understand arbitrary text.


4. Consider NDJSON for ETL Pipelines

A data pipeline may look like:

Database
↓
Extract
↓
NDJSON
↓
Transform
↓
Validate
↓
Load

Processing line by line means the pipeline does not necessarily need to hold the entire dataset in memory.


5. Add JSON Schema Validation Where Appropriate

Using JSON does not automatically guarantee that a message has the structure your application expects.

For example, this is valid JSON:

{
"customerId": "banana"
}

But your API may require:

{
"customerId": 123
}

Schema validation can help enforce contracts between systems.

The same concept applies to NDJSON.

Each individual record can be validated against the expected schema.


6. Include Format Decisions in Architecture Reviews

Teams can add a simple question to architecture reviews:

What is the expected size and processing model of this dataset?

Then evaluate:

Small structured message
↓
JSON
Large independent records
↓
NDJSON
Huge datasets requiring random access
↓
Consider database/object storage/
columnar formats
Binary high-performance messaging
↓
Consider Avro/Protobuf/etc.

Choosing a format should be based on system requirements rather than automatically selecting JSON for everything.


7. Add Large Dataset Tests

Testing should include more than small sample JSON files.

If an endpoint may eventually return one million records, test realistic datasets.

Measure:

  • Memory consumption
  • CPU utilization
  • Response time
  • Time to first record
  • Network bandwidth
  • Garbage collection
  • Client parsing behavior

A design that works perfectly with 50 records may behave very differently with 5 million.


8. Establish Team Guidelines

Development teams can establish simple standards such as:

Use JSON for:

  • Normal REST requests
  • Normal REST responses
  • Configuration
  • Small and medium structured documents
  • Commands
  • API errors
  • Domain objects

Consider NDJSON for:

  • Large exports
  • Streaming endpoints
  • Structured logs
  • ETL pipelines
  • Event archives
  • AI datasets
  • Bulk processing
  • Record-by-record transformations

Having these guidelines prevents developers from making inconsistent decisions across services.


A Simple Decision Tree

When choosing between JSON and NDJSON, start with this question:

Do I have one structured document?
|
Yes
|
JSON

If not:

Do I have many independent records?
|
Yes
|
Is the dataset small?
/ \
Yes No
| |
JSON Array NDJSON

Then ask:

Do I need streaming?
|
Yes
|
NDJSON

And:

Do I need to append records continuously?
|
Yes
|
NDJSON

This is not an absolute rule, but it is a useful starting point.


JSON Is Not Always the Answer

JSON has become so common that developers sometimes use it without considering alternatives.

But different problems may require different representations.

For example:

REST API
→ JSON
Streaming records
→ NDJSON
Tabular analytics
→ CSV / Parquet
High-performance RPC
→ Protocol Buffers
Event serialization
→ JSON / Avro / Protobuf
Large analytical datasets
→ Parquet
Configuration
→ JSON / YAML / TOML

Good architecture is not about selecting the most popular technology.

It is about selecting the technology that matches the problem.


Final Thoughts

JSON and NDJSON are closely related, but they solve different types of data-exchange problems.

JSON is excellent when we want to represent a complete structured document.

{
"customer": {...},
"orders": [...],
"preferences": {...}
}

NDJSON is excellent when we have many independent records that should be processed sequentially.

{"event":1}
{"event":2}
{"event":3}

The most important distinction can be summarized simply:

JSON is document-oriented.

NDJSON is record- and stream-oriented.

For ordinary REST APIs, configuration files, and structured application messages, JSON will usually remain the preferred choice.

For massive exports, structured logs, streaming APIs, ETL pipelines, AI datasets, and other record-by-record workloads, NDJSON can provide a simpler and significantly more scalable approach.

Software engineers should therefore avoid asking whether JSON or NDJSON is universally better.

Instead, ask:

Does my consumer need the entire data structure, or can it process one record at a time?

That single question will often reveal which format is the better architectural choice.