Design a News Feed

By the Syncfusion DevTutorials team · Last updated

Build QuickBite's food feed: pull vs push, fan-out through a queue, the big-account problem, hybrid feeds and a replicated feed cache.

QuickBite is adding a food feed. Customers follow restaurants they like. Restaurants post new dishes, offers and photos. When a customer opens the app, the feed shows the latest posts from followed restaurants, ordered from newest to oldest.

At first glance, this seems like a simple database query.

However, the challenge appears when thousands of customers open the feed at the same time and a large restaurant chain with hundreds of thousands of followers publishes a new promotion.

This is the classic news feed problem, similar to the timeline systems used in large social media platforms.

The main idea is simple: decide when the feed should be built. Build it when users read it (Pull), build it when restaurants create posts (Push), or combine both approaches (Hybrid).

What You Will Learn

In this case study, you will:

  1. Write the requirements for a food feed.
  2. Estimate read traffic, posting traffic and fan-out work.
  3. Compare Pull and Push feed generation.
  4. Understand why large accounts create scaling problems.
  5. Learn how Hybrid feeds solve those problems.
  6. Store prebuilt feeds in cache for fast delivery.
  7. Build and test a scalable feed architecture.

This lesson builds on concepts from Caching, Database Replication, Partitioning and Background Processing.

Step 1: Requirements

What It Must Do (Functional)

  • Create posts containing dishes, offers and photos.
  • Follow and unfollow restaurants.
  • Display a personalized feed containing posts from followed restaurants.
  • Show posts newest first.
  • Load more posts as customers scroll.

How Well It Must Do It (Non-Functional)

  • Feed loading should remain under 100 ms (p99).
  • New posts should appear in feeds within 5 seconds.
  • The feed should scale for heavy read traffic.
  • The system should remain affordable.
  • The system should continue operating during machine failures.

Out of Scope

The first version does not include:

  • Machine-learning ranking
  • Comments
  • Likes
  • Recommendations
  • Trending content

Posts are displayed strictly in reverse chronological order.

Step 2: Estimate

Feed systems are heavily read-oriented.

Suppose QuickBite experiences:

  • 8,000 feed opens every second
  • 40 new posts every second
  • Each customer follows approximately 40 restaurants
NumberValue
Reads per post8,000 ÷ 40 = 200
Pull: posts looked up per second8,000 × 40 = 320,000

What to notice:

  • Feed opens are 200 times more common than posts.
  • A pull design must look at posts from followed restaurants every time the feed opens.
  • At peak traffic, that means 320,000 post lookups every second.
  • This number drives the feed design.

Now look at the other side of the problem.

When a restaurant publishes a post, how many feeds need to be updated?

That depends on how many followers the restaurant has.

The chart shows the fan-out work for one post, if feed writes run at 100,000 a second:

A café post means 2,000 feed writes (0.02 s). A national chain's post means 500,000 feed writes (5.00 s).

A single post from a large restaurant may require updates to hundreds of thousands of customer feeds.

This fan-out work becomes one of the biggest design challenges.

Step 3: Pull or Push?

Pull: Build the Feed When It Is Read

Store each post once. When a customer opens the feed, find followed restaurants, fetch recent posts, merge them and return the newest results.

  • Good: posting is fast and inexpensive.
  • Good: follows and unfollows take effect immediately.
  • Bad: every feed request becomes expensive.
  • Bad: the database performs a large number of lookups.

At peak traffic, the database may need to perform approximately 320,000 post lookups every second.

Pull makes writes inexpensive but reads expensive.

Push: Build the Feed When Posts Are Written

Maintain a ready-made feed for every customer. When a restaurant posts, a background process copies the post reference into follower feeds.

The copied content usually contains only post IDs rather than full post content.

  • Good: feed reads become extremely fast.
  • Good: opening the feed usually requires only a cache lookup.
  • Bad: one post can generate thousands or hundreds of thousands of feed updates.
  • Bad: feed freshness depends on fan-out speed.

This process is called fan-out.

Step through two posts from Spice Garden, which has three followers:

Here is the same idea in code:

Push turns one post into one write per follower

const feeds = new Map(); // customer -> list of post ids, newest first
const followers = { "spice-garden": ["asha", "ravi", "meera"] };

function post(restaurant, postId) {
  for (const customer of followers[restaurant] ?? []) {
    const feed = feeds.get(customer) ?? [];
    feeds.set(customer, [postId, ...feed].slice(0, 200)); // keep the newest 200
  }
}

post("spice-garden", "p1");
post("spice-garden", "p2");
console.log(`ravi's feed: ${feeds.get("ravi").join(", ")}`);
console.log(`Feed writes so far: ${[...feeds.values()].reduce((t, f) => t + f.length, 0)}`);

Expected output:

ravi's feed: p2, p1
Feed writes so far: 6

Notice the last step. Each feed keeps only the newest 200 IDs, so memory stays small. Older posts can be loaded from the database when needed.

Fan-out should never happen during the user request. Store the post, put a fan-out job on a queue, and let background workers update follower feeds. Posting stays fast, and the workers can scale on their own.

Step 4: The Big-Account Problem and Hybrid

Push works well for ordinary restaurants.

It breaks down for extremely popular accounts.

Consider a national restaurant chain with:

  • 500,000 followers

One post requires:

  • 500,000 feed updates

Fan-out workers spend significant time processing that single post.

Meanwhile:

  • Smaller restaurant posts wait.
  • Queue delay increases.
  • Feed freshness decreases.

This is commonly called the celebrity problem.

Hybrid combines Pull and Push.

Rule:

  • Normal accounts use Push.
  • Large accounts use Pull.

For ordinary restaurants:

  • Posts are pushed into follower feeds.

For very large accounts:

  • Posts are stored separately.
  • Fan-out is skipped.
  • Posts are merged into feeds at read time.

When a customer opens the feed:

  1. Read pushed posts.
  2. Read recent large-account posts.
  3. Merge results.
  4. Return newest content.

Step through one feed read that merges both kinds of posts:

Here is the same idea in code:

Hybrid: merge pushed posts with pulled big-chain posts

const pushedFeed = [
  { id: "p9", at: 1050 },
  { id: "p7", at: 1010 },
];
const bigChainPosts = [
  { id: "b3", at: 1040 },
  { id: "b2", at: 990 },
];

const feed = [...pushedFeed, ...bigChainPosts].sort((a, b) => b.at - a.at).slice(0, 3);
console.log(feed.map((p) => p.id).join(", "));

Expected output:

p9, b3, p7

What to notice:

  • Most customers follow only a few huge accounts.
  • Hybrid removes expensive fan-out work from those accounts.
  • Read performance remains fast.
  • Feed freshness improves because workers spend less time processing giant fan-out jobs.

Hybrid combines the best parts of Push and Pull.

Step 5: The High-Level Design

A feed has two busy paths.

Reading a feed:

  1. Customer opens the app.
  2. Request reaches the load balancer.
  3. Feed service receives the request.
  4. Ready-made feed is loaded from the feed cache.
  5. Large-account posts are merged.
  6. Post details are fetched from cache or database.
  7. Response is returned.

At peak traffic this path handles approximately:

  • 8,000 feed requests per second

Posting:

  1. Restaurant creates a post.
  2. Feed service saves the post.
  3. A fan-out job enters the queue.
  4. Fan-out workers process followers.
  5. Feed cache is updated.

At peak traffic this path handles approximately:

  • 40 posts per second

Store only post IDs rather than full post content.

Example:

Customer Feed

  • Post 101
  • Post 102
  • Post 103

Post content is stored separately and shared between feeds.

How big is the feed cache? Work it out for 2,000,000 customers:

ItemValue
Post IDs per feed200
Bytes per ID8
Copies of each feed2
Total2,000,000 × 200 × 8 × 2 = 6.4 GB

Ready-made feeds for every customer fit in a few cache nodes.

Keep only the newest 200 post IDs in memory.

Older posts can be loaded from the database when needed.

Rebuilding feeds is expensive, so keep two copies of every feed on separate cache nodes. If one node fails, feeds stay available and you avoid a costly rebuild.

Step 6: Build It on the Canvas and Test It

Open the design sandbox.

The canvas starts with:

  • 2 load balancers
  • 4 feed servers running Pull
  • 2 database copies

Select the feed servers to switch between Pull, Push and Hybrid.

Select the cache to choose one or two copies of each feed.

CheckPasses when
Peak loadFeed p99 at most 100 ms with fewer than 0.1% errors, and new posts reach feeds within 5 s (p99)
Lose any one machineAny one load balancer, feed server, cache node, database copy or worker dies. Errors under 1%, p99 under 250 ms, posts still delivered within 10 s
CostAt most $1,500 a month
RequirementsFan-out runs in the background, through a queue and workers

Make the QuickBite food feed fast and fresh

Run the pull design first and watch the database. Then try push and then hybrid.

What you will probably find:

  • Pull overloads the database because every feed read performs many lookups.
  • Push makes reads extremely fast but struggles with huge follower counts.
  • Hybrid removes the celebrity bottleneck while keeping reads fast.
  • One feed copy is not enough because cache failures trigger expensive feed rebuilds.

A design that passes:

  • 2 load balancers
  • 4 feed servers
  • Hybrid feed generation
  • 2 cache nodes with two feed copies
  • 2 database replicas
  • Queue service
  • 2 fan-out workers

This design provides:

  • Fast feed reads
  • Fresh posts
  • High reliability
  • Acceptable operational cost

while remaining within budget.

Common Mistakes

MistakeWrongCorrectWhy It Happens
One big queryBuild the feed entirely during readsUse Push or Hybrid approachesSmall datasets hide the problem
Fan-out during postingUser waits for every feed updateUse queues and workersSimpler implementation
Push for everyoneFan out large-account postsUse Hybrid for large accountsAverage follower counts appear small
Unlimited feed sizeStore all post IDs foreverKeep only recent postsMemory growth is ignored initially
Single cache copyDepend on one feed copyKeep multiple copiesFeed cache is mistaken for a simple cache

Practice

What to Remember

  • A feed system is mostly a decision about when work happens.
  • Pull builds feeds during reads.
  • Push builds feeds during writes.
  • Hybrid combines both approaches.
  • Reads usually outnumber writes by a large margin.
  • Fan-out should run through queues and workers.
  • Large accounts create the celebrity problem.
  • Hybrid designs prevent large fan-out spikes.
  • Store only post IDs inside feeds.
  • Keep multiple feed copies for reliability.
  • Fast feed reads depend on caching.

Further Reading

These are the sources this lesson was checked against:

Next: Chat, where customers and riders communicate with each other in real time.