Search

Software Engineer's Notes

Tag

Data Engineering

Cold Start in Recommender Systems: A Practical Guide for Software Teams

Recommender systems are everywhere. Netflix recommends movies, Spotify recommends music, Amazon recommends products, YouTube recommends videos, and social media platforms recommend posts, accounts, and communities.

Most of these systems become better as they collect more information about users and items. They learn what users click, purchase, watch, skip, rate, save, or ignore.

But what happens when there is no history?

What should an application recommend to a user who registered ten seconds ago?

How should an e-commerce platform decide who might be interested in a product that was added five minutes ago?

And what happens when we launch an entirely new platform where there are no users, interactions, ratings, or historical patterns at all?

These situations create what is known as the cold start problem.

Cold start is one of the fundamental challenges in recommender-system engineering because many recommendation algorithms depend heavily on historical interaction data. Understanding cold start is therefore important not only for data scientists, but also for software engineers designing applications that contain personalization, search, ranking, recommendation, or discovery features.

In this article, we will explore what cold start is, where the concept came from, the different types of cold start, how recommender systems handle it, common solutions, and how we can incorporate cold-start strategies into our existing software development process.

What Is Cold Start in Recommender Systems?

What is cold start?

Cold start describes a situation where a recommender system does not have enough information to generate reliable personalized recommendations.

Consider a movie recommendation system.

After a user has watched hundreds of movies, the system may know that the user:

  • frequently watches science-fiction movies,
  • likes Christopher Nolan films,
  • rarely watches romantic comedies,
  • usually watches documentaries on weekends,
  • finishes most space-related movies,
  • and frequently gives thrillers a positive rating.

The recommendation engine has a rich behavioral profile that it can use.

Now imagine another user who has just created an account.

The system knows almost nothing about that person.

There are no:

  • movie views,
  • ratings,
  • searches,
  • likes,
  • skips,
  • watch-time records,
  • or browsing patterns.

The recommendation system is effectively starting from zero.

This is a user cold start.

Cold start can also occur on the other side of the recommendation relationship.

Imagine that a new movie has just been added to the platform.

No users have watched it yet.

If the recommendation algorithm depends primarily on collaborative behavior such as:

People who watched Movie A also watched Movie B

the new movie has no interaction history and therefore cannot easily participate in those calculations.

This is an item cold start.

At its core, cold start is therefore a lack-of-information problem.

Why Does Cold Start Happen?

Many recommender systems learn from relationships between users and items.

Imagine a simplified interaction matrix:

UserMovie AMovie BMovie CMovie D
User 154?2
User 2554?
User 3?451
New User????

The system can detect similarities between Users 1, 2, and 3 because they have provided information through ratings or behavior.

The new user has contributed nothing.

There is no statistical relationship to analyze.

A similar problem occurs with a newly added item:

UserMovie AMovie BMovie CNew Movie
User 1543?
User 2454?
User 3345?

Pure collaborative filtering has very little information with which to determine who should receive the new movie as a recommendation.

This is why cold start is especially problematic for systems that rely heavily on collaborative filtering.

A Brief History of the Cold Start Problem

The cold start problem grew naturally out of the development of collaborative filtering.

Early recommender systems began becoming prominent during the 1990s as researchers looked for ways to help users navigate increasing amounts of online information.

One influential example was GroupLens, introduced in the 1990s for filtering Usenet news articles. GroupLens used collaborative filtering principles: users who had agreed on articles in the past could help predict which other articles they might like in the future.

This approach introduced an obvious dependency:

Collaborative filtering needs collaboration data.

Without ratings, clicks, purchases, or other interactions, there is little information from which relationships can be calculated.

As recommendation research matured, researchers increasingly studied the problem explicitly. A notable milestone was the 2002 paper “Methods and Metrics for Cold-Start Recommendations” by Andrew Schein, Alexandrin Popescul, Lyle Ungar, and David Pennock. The researchers examined recommendations for items that had not yet received ratings and explored methods combining collaborative and content information.

Since then, cold start has remained an important research and engineering problem.

Modern approaches have expanded beyond traditional collaborative filtering and now include:

  • content-based recommendation,
  • hybrid recommendation systems,
  • demographic information,
  • contextual signals,
  • embeddings,
  • neural networks,
  • transfer learning,
  • multi-armed bandits,
  • graph-based recommendation,
  • and increasingly semantic representations generated from text, images, audio, and other content.

Despite increasingly sophisticated algorithms, the fundamental challenge remains unchanged:

How can we make a good prediction when we have very little evidence?

The Main Cold Start Cases

Cold start is often described as two main cases: new user and new item.

In production systems, however, it is useful to think about at least three major categories.

1. New User Cold Start

A new user enters the application without an interaction history.

For example, someone creates an account on a music streaming platform.

The platform does not yet know:

  • preferred artists,
  • favorite genres,
  • listening times,
  • skipped songs,
  • completed songs,
  • playlists,
  • or search behavior.

Collaborative filtering cannot easily identify similar users because there is no behavioral profile to compare.

This is probably the most recognizable form of cold start.

One common solution is to collect a small amount of information during onboarding.

For example:

Choose three genres you like:

  • Rock
  • Jazz
  • Classical
  • Hip Hop
  • Electronic
  • Country

Or:

Choose five movies you enjoyed.

The recommendation engine can immediately use those selections to create an initial preference profile.

Netflix, for example, explains that new profiles may select titles they like to help “jump start” recommendations. If the user does not choose titles, Netflix can initially provide a diverse and popular selection. As the user interacts with the service, behavioral signals increasingly drive recommendations.

This illustrates an important recommender-system principle:

Cold-start recommendations do not have to be perfect. They need to be good enough to encourage the interactions that will improve future recommendations.

2. New Item Cold Start

The second case occurs when a new item enters the catalog.

Examples include:

  • a newly released movie,
  • a new product,
  • a recently published article,
  • a new restaurant,
  • a new job posting,
  • a newly uploaded video,
  • or a new song.

The system may know a lot about existing users but almost nothing about how users will interact with the new item.

For collaborative filtering, this is particularly challenging because the item has no collaborative history.

However, unlike a completely unknown user, items often have useful metadata.

A movie may have:

  • title,
  • genre,
  • director,
  • actors,
  • description,
  • release year,
  • language,
  • keywords,
  • and content rating.

An e-commerce product may have:

  • category,
  • brand,
  • description,
  • price,
  • specifications,
  • color,
  • manufacturer,
  • and images.

A content-based recommender can use these attributes even before anyone interacts with the item.

3. New System or New Community Cold Start

The most extreme cold-start case happens when the recommendation system itself is new.

Imagine launching a new marketplace.

There may initially be:

  • 50 products,
  • 20 customers,
  • very few purchases,
  • almost no ratings,
  • and no meaningful behavioral history.

In this situation, both users and items are cold.

This is sometimes called the new-community problem or system cold start.

Pure collaborative filtering is usually ineffective because the interaction matrix is nearly empty.

Early recommendations may therefore depend heavily on:

  • popularity,
  • curated recommendations,
  • business rules,
  • content similarity,
  • demographic information,
  • contextual information,
  • imported historical data,
  • or external datasets.

As the platform collects interactions, machine-learning models can gradually replace or complement these initial strategies.

Strict Cold Start vs. Partial Cold Start

Cold start does not always mean that absolutely no information exists.

It can exist on a spectrum.

Strict Cold Start

There is essentially no historical information.

For example:

New user:

Clicks = 0
Purchases = 0
Ratings = 0
Searches = 0

Partial Cold Start

A small amount of data exists, but not enough to build a reliable profile.

For example:

Clicks = 3
Purchases = 0
Ratings = 1

Production systems should usually distinguish between these states.

A user with zero interactions may receive popularity-based recommendations.

After three interactions, the system might start blending content-based personalization.

After twenty interactions, collaborative filtering may become reliable.

This creates a progressive recommendation strategy rather than treating every user identically.

How Does a Recommender System Handle Cold Start?

There is no single universal cold-start algorithm.

Instead, systems typically combine several strategies.

Popularity-Based Recommendations

The simplest solution is recommending what is currently popular.

For example:

New User
↓
No history available
↓
Retrieve popular items
↓
Apply basic filters
↓
Return recommendations

Possible signals include:

  • most purchased,
  • most watched,
  • trending,
  • highest rated,
  • most clicked,
  • recently popular,
  • or popular within a geographic region.

Popularity provides a strong baseline because popular items are statistically more likely to appeal to a random user than randomly selected items.

However, it provides limited personalization.

Content-Based Filtering

Content-based systems examine the characteristics of items.

Suppose a user selects:

Interstellar

The system might examine features such as:

Genre: Science Fiction
Director: Christopher Nolan
Topics: Space, Time, Exploration
Release period: 2010s

It can then find similar items.

Content-based recommendation is particularly useful for item cold start because new items may have rich metadata even if they have no interaction history.

Modern systems can also represent content as embeddings.

For example:

Item description
↓
Embedding model
↓
Vector representation
↓
Vector similarity search
↓
Similar items

This can allow a new item to immediately participate in recommendations.

User Onboarding

Instead of waiting for users to generate behavioral signals, we can ask them directly.

Examples include:

  • Select topics you are interested in.
  • Choose five movies you like.
  • Follow at least three creators.
  • Select your favorite categories.
  • Tell us your preferred price range.

The result may become an initial preference vector.

New User
↓
Onboarding Preferences
↓
Initial User Profile
↓
Content Matching
↓
Initial Recommendations

The important UX consideration is not to make onboarding so long that users abandon the application.

There is usually a tradeoff:

More onboarding questions
↓
Better initial personalization
↓
Higher onboarding friction

The best systems collect the minimum amount of information necessary to produce useful initial recommendations.

Demographic and Contextual Information

Some applications can use contextual information such as:

  • country,
  • language,
  • device,
  • time of day,
  • location,
  • age range when appropriate and permitted,
  • selected interests,
  • referral source,
  • current page,
  • or session behavior.

For example:

New User
Language: English
Country: United States
Device: Mobile
Current category: Running Shoes

Even without long-term history, the system can make more useful recommendations than simply returning random products.

Privacy and fairness must be carefully considered whenever demographic information is involved.

Hybrid Recommendation Systems

Hybrid systems combine multiple recommendation strategies.

For example:

Recommendation Score =
Collaborative Score
+ Content Score
+ Popularity Score
+ Context Score

The weights can change depending on how much information exists.

For a new user:

Popularity 50%
Content 35%
Context 15%
Collaborative 0%

After the user generates more activity:

Popularity 10%
Content 25%
Context 10%
Collaborative 55%

This dynamic weighting is extremely useful in production systems.

Research literature frequently identifies hybrid methods as an important way to address cold-start limitations because they can use content or auxiliary information while collaborative data remains sparse.

Exploration and Exploitation

Another important concept is deciding whether to recommend something the system already believes the user will like or experiment with something uncertain.

This is the classic exploration vs. exploitation problem.

Exploitation

Recommend items that already have a high predicted probability of success.

Example:

The user likes Java programming, so recommend another Java article.

Exploration

Occasionally recommend something less certain.

Example:

The user likes Java, but let’s test whether they are also interested in Kubernetes.

If the user clicks the Kubernetes article, the system has discovered an additional preference.

Techniques such as multi-armed bandits can help balance exploration and exploitation.

This is especially valuable for cold start because the recommendation system needs to actively collect information.

Cold Start as a Feedback Loop

One of the best ways to understand the problem is as a feedback loop.

Initial Recommendation
↓
User Interaction
↓
Collect Signals
↓
Update User Profile
↓
Improve Recommendation
↓
More Interaction
↓
More Data
↓
Better Recommendation

Cold start is primarily the challenge at the beginning of this loop.

Once sufficient interactions are collected, the system becomes increasingly personalized.

Therefore, a good cold-start strategy does more than generate useful recommendations.

It should also accelerate learning.

What Signals Should We Collect?

Different interactions have different strengths.

Explicit Signals

The user deliberately tells the system something.

Examples:

  • ratings,
  • likes,
  • dislikes,
  • selected interests,
  • favorites,
  • reviews.

For example:

User rated Item A = 5 stars

This is a strong signal.

Implicit Signals

The application observes user behavior.

Examples:

  • clicks,
  • purchases,
  • watch time,
  • scroll depth,
  • search queries,
  • add-to-cart events,
  • article completion,
  • video completion,
  • repeated views,
  • skips.

For example:

Video started
Video watched for 45 minutes
Video duration = 47 minutes

This may strongly indicate interest even though the user never clicked a Like button.

Modern recommendation systems commonly rely heavily on implicit feedback because it can be collected continuously without requiring additional effort from users.

Example: E-Commerce Cold Start

Imagine an online store.

A new visitor arrives.

There is no profile.

The initial recommendation pipeline might be:

Request
↓
Is user known?
↓
No
↓
Determine current context
↓
Retrieve popular products
↓
Apply category relevance
↓
Apply availability filter
↓
Apply geographic constraints
↓
Rank products
↓
Return recommendations

After the user searches for:

mechanical keyboard

the recommendation strategy changes.

The application now knows something about the current intent.

Recommendations might include:

  • mechanical keyboards,
  • switches,
  • keycaps,
  • wrist rests,
  • keyboard cables.

After additional browsing and purchases, the recommendation engine can transition toward collaborative personalization.

Example: Software Engineering Blog

Cold start is not limited to massive platforms like Netflix or Amazon.

Imagine a technical blog containing articles about:

  • Java,
  • Spring Boot,
  • Kubernetes,
  • AI,
  • databases,
  • software architecture,
  • testing,
  • security,
  • and DevOps.

A completely new visitor arrives.

There is no profile.

The site might initially display:

Most Popular Articles
Trending This Week
Recently Published
Editor's Picks

The visitor reads:

Feature Flags in Software Development

The recommender can now infer interest in:

Software Delivery
DevOps
Release Strategies
Continuous Delivery

The next recommendations could include:

Dark Launches
A/B Testing
Canary Releases
Blue-Green Deployments
Feature Toggles

As the visitor reads more articles, the recommendations become increasingly personalized.

This illustrates an important point:

You do not need enormous amounts of AI infrastructure to implement useful cold-start logic.

Simple business rules combined with good event tracking can provide substantial value.

How Can We Integrate Cold-Start Handling into Our Software Development Process?

Cold start should not be treated as a problem that belongs exclusively to a machine-learning team.

It affects:

  • architecture,
  • UX,
  • APIs,
  • databases,
  • analytics,
  • observability,
  • product design,
  • testing,
  • and deployment.

A practical implementation can be divided into several stages.

Step 1: Define Recommendation Scenarios

First determine where recommendations exist.

Examples:

Homepage recommendations
Related products
Related articles
People to follow
Recommended videos
Recommended jobs
Recommended courses

For each scenario, ask:

What happens if we know nothing about the user?

and:

What happens if the item has no interactions?

These questions should become part of the feature’s requirements.

Step 2: Define Cold-Start States

Instead of simply checking whether a user is new, define meaningful states.

For example:

COLD
0 interactions
EARLY
1–5 interactions
LEARNING
6–20 interactions
WARM
20+ interactions

Your thresholds will depend on the application.

The recommendation service can expose this state internally:

{
"userId": "12345",
"recommendationState": "EARLY",
"interactionCount": 4
}

Different strategies can then be applied.

Step 3: Build a Reliable Fallback

Every recommendation endpoint should have a fallback.

For example:

Personalized Model
↓
Enough data?
↙ ↘
Yes No
↓ ↓
Model Popularity
Results Results

Never allow the application to display:

No recommendations available.

simply because the machine-learning model lacks data.

Fallbacks can include:

  • popular items,
  • trending items,
  • recent items,
  • editor selections,
  • category-based items,
  • or business-curated recommendations.

Step 4: Build an Event Collection Layer

Recommendation quality depends heavily on telemetry.

Create consistent events such as:

ITEM_VIEWED
ITEM_CLICKED
ITEM_LIKED
ITEM_DISLIKED
ITEM_PURCHASED
ITEM_SKIPPED
SEARCH_PERFORMED
ITEM_SAVED
ITEM_COMPLETED

An event might look like:

{
"event": "ITEM_VIEWED",
"userId": "12345",
"itemId": "98765",
"timestamp": "2026-08-26T18:30:00Z",
"context": {
"source": "recommendation",
"position": 3
}
}

These events become the raw material for future personalization.

Step 5: Create Item Metadata

Good item metadata dramatically improves item cold start.

Depending on the application, metadata might include:

category
tags
description
keywords
author
brand
language
price
topics
location
creation date

For text-heavy applications, embeddings can supplement manually assigned metadata.

For example:

Article published
↓
Generate embedding
↓
Store vector
↓
Find semantically similar articles
↓
Article immediately becomes recommendable

The item does not need to wait for thousands of clicks before appearing in useful recommendations.

Step 6: Add a Recommendation Service

Avoid embedding recommendation logic directly throughout the frontend.

Create a clear service boundary.

For example:

Frontend
↓
Recommendation API
↓
Recommendation Strategy
├── Cold User Strategy
├── Early User Strategy
├── Personalized Strategy
├── Cold Item Strategy
└── Fallback Strategy

An API might look like:

GET /api/recommendations?userId=123&type=homepage

Internally:

RecommendationService
↓
Determine user state
↓
Select strategy
↓
Generate candidates
↓
Rank candidates
↓
Apply business rules
↓
Return results

This architecture makes algorithms easier to evolve without rewriting the user interface.

Step 7: Use the Strategy Pattern

Cold-start logic is a good candidate for the Strategy Pattern.

Conceptually:

RecommendationStrategy
├── PopularityRecommendationStrategy
├── ContentRecommendationStrategy
├── CollaborativeRecommendationStrategy
└── HybridRecommendationStrategy

The system selects a strategy depending on available data.

For example:

if (interactionCount == 0) {
return popularityStrategy.recommend(user);
}
if (interactionCount < 10) {
return contentStrategy.recommend(user);
}
return hybridStrategy.recommend(user);

Real implementations will usually be more sophisticated, but this architecture separates concerns effectively.

Step 8: Separate Candidate Generation from Ranking

Production recommender systems often use two broad stages.

Candidate Generation

Retrieve potentially relevant items.

Examples:

Popular items
Similar items
Collaborative candidates
Recently trending items
Semantic matches

Perhaps this generates:

10,000 candidates

Ranking

A ranking model determines which candidates are most useful.

10,000 candidates
↓
Ranking
↓
Top 20 recommendations

Cold-start strategies can participate in candidate generation alongside mature recommendation models.

This provides flexibility.

Step 9: Measure Cold Users Separately

One common mistake is evaluating the entire recommendation system with a single metric.

Suppose the average click-through rate is:

CTR = 8.3%

That number hides important information.

Instead measure:

Cold users: 3.1%
Early users: 5.8%
Warm users: 11.2%

Similarly, measure new items separately.

Useful metrics include:

  • click-through rate,
  • conversion rate,
  • watch time,
  • engagement rate,
  • precision,
  • recall,
  • NDCG,
  • coverage,
  • diversity,
  • novelty,
  • time to first interaction,
  • time to warm state.

One particularly useful product metric is:

How quickly does a user leave the cold-start state?

For example:

Median time to 5 meaningful interactions = 18 minutes

Reducing this time may improve the entire recommendation system.

Step 10: Use A/B Testing

Cold-start strategies should be experimentally evaluated.

For example:

Variant A

Popular Items

Variant B

Onboarding Interests + Popular Items

Variant C

Onboarding + Content Recommendations

Then compare:

CTR
Session duration
Conversion
Retention
Number of interactions
Cold-to-warm transition time

The technically most advanced algorithm is not necessarily the best product experience.

Step 11: Monitor Recommendation Quality

Recommendation systems can degrade silently.

Monitor signals such as:

Recommendation API latency
Empty recommendation rate
Fallback usage rate
Cold-user percentage
Cold-item percentage
CTR
Conversion
Model confidence
Candidate count

A particularly useful metric is:

fallback_rate

If it suddenly increases from:

5%

to:

60%

the personalized recommender may have failed even though the API continues returning HTTP 200 responses.

Step 12: Continuously Improve the Model

A recommendation architecture should allow gradual evolution.

Phase 1

Popularity

Phase 2

Popularity + Categories

Phase 3

Content-Based Recommendation

Phase 4

Collaborative Filtering

Phase 5

Hybrid Recommendation

Phase 6

Embeddings + Learned Ranking

Phase 7

Exploration + Continuous Learning

This approach is usually more practical than attempting to build a sophisticated AI recommender before enough data exists.

A Practical Architecture

A simplified production architecture might look like this:

                User
                  ↓
             Application
                  ↓
        Recommendation API
                  ↓
        Recommendation Router
          ↙        ↓        ↘
    Cold User   Warm User   Cold Item
       ↓            ↓           ↓
   Popularity   Collaborative  Content
   + Context      Filtering    Similarity
          ↘        ↓        ↙
          Candidate Generator
                  ↓
                Ranker
                  ↓
           Business Rules
                  ↓
          Recommendations
                  ↓
             User Actions
                  ↓
             Event Stream
                  ↓
          Analytics / Storage
                  ↓
            Model Training

The key principle is that cold-start handling should be part of the architecture rather than an emergency fallback added later.

Common Mistakes

Several mistakes frequently appear when teams first implement recommender systems.

Random Recommendations

Random recommendations may provide diversity, but pure randomness generally creates poor user experiences.

Use popularity, context, or content similarity as a baseline.

Waiting for Enough Data

A team may say:

We will implement recommendations after we have enough data.

But recommendations themselves can generate the interactions needed for better recommendations.

Start with simple strategies and evolve them.

Too Much Onboarding

Asking users to rate 50 items may improve the initial profile but dramatically increase abandonment.

Ask for a small number of high-information preferences.

Ignoring New Items

A recommender that heavily favors items with historical interactions can create a self-reinforcing system:

Popular Item
↓
More Recommendations
↓
More Clicks
↓
More Training Data
↓
Even More Recommendations

Meanwhile:

New Item
↓
No Interactions
↓
No Recommendations
↓
Still No Interactions

The new item never gets an opportunity to become popular.

Exploration strategies and content-based recommendation can help break this cycle.

Using Only Accuracy

A recommendation engine that always recommends extremely popular products may achieve respectable click-through rates while offering little discovery.

Evaluate:

  • diversity,
  • novelty,
  • catalog coverage,
  • fairness,
  • and exposure,

in addition to accuracy.

Treating Cold Start as Only an ML Problem

Cold start affects the entire product.

Solutions can include:

UX
+
Data Collection
+
Backend Architecture
+
Business Rules
+
Machine Learning
+
Experimentation

Sometimes a simple onboarding screen can solve more of the problem than another six months of model development.

Best Practices

When designing cold-start handling, consider the following principles.

Always provide a fallback.

The recommendation system should produce something useful even if personalization fails.

Collect useful signals early.

Clicks, searches, views, skips, likes, and purchases quickly improve user understanding.

Keep onboarding short.

Collect enough information to get started without creating excessive friction.

Invest in item metadata.

Good metadata makes new items immediately usable by content-based systems.

Use hybrid approaches.

Do not force one algorithm to solve every recommendation scenario.

Separate cold and warm users.

Different information states require different strategies.

Allow exploration.

New users and new items require opportunities for the system to learn.

Measure cold-start performance separately.

Average recommendation metrics can hide serious cold-start problems.

Design cold start from the beginning.

Do not assume the recommendation model will somehow solve it automatically.

Cold Start and Modern AI

Modern AI does not eliminate the cold-start problem, but it gives us more tools to reduce it.

For example, large language models and embedding models can extract meaningful representations from:

  • text,
  • product descriptions,
  • documentation,
  • reviews,
  • images,
  • user queries,
  • and other unstructured content.

Consider a newly published article titled:

Understanding Event-Driven Architecture with Apache Kafka

Even if nobody has read it yet, an embedding model may recognize semantic relationships with existing content about:

Kafka
Message Queues
Microservices
Event-Driven Architecture
Distributed Systems
Asynchronous Communication

The article can immediately become a recommendation candidate.

Similarly, modern neural approaches can combine user attributes, item attributes, contextual signals, and behavioral histories in a single learned representation. Neural networks and hybrid approaches continue to be actively researched as methods for dealing with sparse and cold-start recommendation scenarios.

However, AI does not change the fundamental principle.

If the system knows nothing about the user, it must obtain useful information from somewhere.

That information might come from:

User onboarding
Context
Item content
Population behavior
External knowledge
Session behavior
Exploration

Cold start is fundamentally an information problem.

Final Thoughts

The cold start problem is one of the most important practical challenges in recommender systems.

Recommendation algorithms become powerful when they have rich interaction histories, but every user, item, and platform starts somewhere.

The three major cold-start cases are:

  1. New User Cold Start — the system does not yet understand the user’s preferences.
  2. New Item Cold Start — the system does not yet know how users will react to a newly added item.
  3. New System or Community Cold Start — there is not enough historical information about either users or items.

There is no single algorithm that completely solves these problems.

Successful systems typically combine techniques such as:

Popularity
+
Content-Based Recommendation
+
Onboarding
+
Context
+
Collaborative Filtering
+
Hybrid Models
+
Embeddings
+
Exploration

From a software engineering perspective, perhaps the most important lesson is that cold start should be considered during system design rather than after a recommendation model has already been built.

We should define:

What happens with zero data?
What happens with limited data?
What happens with sufficient data?

Then create different strategies for each state.

A mature recommender system does not simply contain an intelligent model.

It contains an intelligent transition from knowing nothing to knowing enough.

And that transition is exactly what solving the cold start problem is about.

JSON vs. NDJSON: What They Are, How They Differ, and When to Use Each

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.

Powered by WordPress.com.

Up ↑