Back to System Design Problems
Q5Question 5 of 13

Design a News Feed / Timeline (like Twitter/Instagram)

Key Concepts
  • Fan-out-on-write pushes new posts into every follower's precomputed feed for fast reads (the common case).
  • Fan-out-on-read assembles the feed on demand by pulling from followed accounts (cheap writes, slow reads).
  • The celebrity problem breaks pure fan-out-on-write: millions of writes for one post from a mega-account.
  • Hybrid approach: fan-out-on-write for normal accounts, pull-on-read for celebrities, merged at read time.
  • Ranking replaces pure chronological order with a score combining recency, engagement, and affinity.
  • Cursor-based pagination is stable when new posts arrive; offset-based pagination causes duplicates or gaps.
  • Accept eventual consistency for feeds: a feed being a few seconds stale harms nobody, unlike a bank balance.

Definition

Push posts into follower feeds at write time for fast reads, pull on read for celebrities, rank instead of pure time order, and cache feeds with cursor pagination.
  • Fan-out-on-write : when someone posts, immediately write the post id into every follower's precomputed feed list.
  • Fan-out-on-read : assemble the feed on demand by pulling recent posts from everyone the user follows.
  • Celebrity problem : a user with millions of followers makes fan-out-on-write prohibitively expensive.
  • Hybrid : fan-out-on-write for normal accounts, pull-on-read for celebrities, merged at read time.
  • Cursor pagination : use the last-seen post id or score as the cursor, stable when new posts arrive.

National Bank of India has an in-app feed where Rajesh sees updates from advisors and channels he follows. Two ways to build it: push every post into each follower's inbox (fan-out-on-write) or gather posts when Rajesh opens the app (fan-out-on-read). The first is fast to read but heavy to write; the second is the opposite. Real banks blend both.

Understanding the Concepts

What is fan-out-on-write?

When someone posts, the system immediately writes that post id into every follower's feed list in a fast store like Redis. Reading is trivial: just fetch the precomputed list. At National Bank of India, when an advisor posts a market update, it is pushed into the feed of every customer who follows that advisor.

JAVA
package com.bank.feed;

import java.util.List;

public class FanOutOnWrite {
    public void onNewPost(String authorId, String postId) {
        List<String> followers = followerStore.of(authorId);
        for (String follower : followers)
            feedCache.prepend(follower, postId);  // Redis LPUSH per follower
    }
}

What is fan-out-on-read?

Nothing is precomputed. When Rajesh opens the feed, the system queries recent posts from every account he follows and merges them by rank. Writes are cheap but reads are expensive because the merge happens on every request.

JAVA
package com.bank.feed;

import java.util.ArrayList;
import java.util.List;

public class FanOutOnRead {
    public List<String> buildFeed(String userId, int limit) {
        List<String> followed = followStore.followedBy(userId);
        List<String> merged = new ArrayList<>();
        for (String author : followed)
            merged.addAll(postStore.recent(author, limit));
        merged.sort(ranking.byScoreDesc());
        return merged.subList(0, Math.min(limit, merged.size()));
    }
}

What is the celebrity problem?

A hugely popular account posting fans out to millions of feeds, which is wasteful and slow. One post from a mega-channel like the bank's official announcements would trigger millions of Redis writes. The hybrid solution uses fan-out-on-write for normal accounts and fan-out-on-read for celebrities, merged at read time.

JAVA
package com.bank.feed;

import java.util.ArrayList;
import java.util.List;

public class HybridFeed {
    public List<String> buildFeed(String userId, int limit) {
        List<String> feed = new ArrayList<>(feedCache.range(userId, 0, limit));
        for (String celeb : celebritiesFollowedBy(userId))
            feed.addAll(postStore.recent(celeb, limit));  // pull on read
        feed.sort(ranking.byScoreDesc());
        return feed.subList(0, Math.min(limit, feed.size()));
    }
}

How does ranking work?

Ranking replaces pure chronological order with a score combining recency, engagement, and affinity. Recency decays over time. Engagement counts likes, shares, and comments. Affinity measures how often the reader interacts with the author. The ranking formula is tuned by the product team and must be updatable without rebuilding all feeds.

JAVA
package com.bank.feed;

public class RankingService {
    public double score(Post post, String readerId) {
        double recency = 1.0 / (1.0 + hoursAgo(post.createdAt()));
        double engagement = post.likes() * 1.0 + post.shares() * 3.0 + post.comments() * 2.0;
        double affinity = interactionScore(readerId, post.authorId());
        return recency * 0.4 + engagement * 0.3 + affinity * 0.3;
    }
}

Why use cursor pagination?

A new post arriving between page loads shifts offset-based pages, causing duplicates or gaps. A cursor based on the last-seen post id or score is stable because it anchors to a specific position in the result set regardless of new inserts.

JAVA
package com.bank.feed;

import java.util.List;

public class CursorPaginator {
    public List<String> nextPage(String userId, String lastSeenPostId, int pageSize) {
        double lastScore = feedCache.scoreOf(userId, lastSeenPostId);
        return feedCache.rangeByScore(userId, lastScore, pageSize);
    }
}

How do you cache feeds?

Cache assembled feeds in Redis with a short TTL (e.g., 60 seconds) and invalidate or append on new posts. Accept eventual consistency: a feed being seconds stale is fine because unlike a bank balance, a slightly outdated feed harms nobody.

How is this different from a chat system?

A chat requires strong ordering and delivery guarantees per conversation. A feed is a ranked list where eventual consistency and approximate ordering are acceptable. Chat messages must never be lost; a feed post appearing a few seconds late is fine.

What should a senior engineer know?

A senior engineer tunes the celebrity threshold (e.g., 100K followers), monitors fan-out latency per percentile, and designs the ranking algorithm to be updatable via configuration without rebuilding all feeds. They also consider A/B testing different ranking formulas and monitoring feed freshness metrics across regions.

Visual Overview

DIAGRAM
  News Feed Architecture

  Post creation:
  ┌──────────┐  new post  ┌──────────────┐
  │  Author  │───────────►│  Post Store  │
  └──────────┘            └──────┬───────┘
                                 │
                    ┌────────────┼────────────┐
                    │ normal     │            │ celebrity
                    │ account    │            │ account
                    ▼            │            │
          ┌──────────────┐      │     (no fan-out,
          │ Fan-out to   │      │      pull on read)
          │ each follower│      │
          │ feed (Redis) │      │
          └──────────────┘      │
                                │
  Feed read:
  ┌──────────┐  open feed  ┌────▼───────────┐
  │  Reader  │────────────►│ Precomputed    │
  │          │             │ feed (Redis)   │
  │          │◄────────────│ + celebrity    │
  │          │  ranked,    │ posts (pulled) │
  │          │  paginated  │ + ranked       │
  └──────────┘             └────────────────┘

Key Takeaway

A news feed system builds a personalized list of posts for each user. The central decision is between fan-out-on-write (fast reads, heavy writes) and fan-out-on-read (cheap writes, slow reads). The celebrity problem breaks pure fan-out-on-write, so the mature solution is a hybrid: fan-out for normal accounts, pull for celebrities, merged at read time.

Ranking replaces pure chronological order, cursor pagination keeps pages stable, and I accept eventual consistency because a stale feed harms nobody.

At National Bank of India, this powered an in-app feed where advisors' tips were fanned out but official announcements from the mega-channel were pulled on read.

Remember one sentence: fan out on write for normal accounts, pull on read for celebrities, rank for relevance, paginate with cursors, and accept eventual consistency for feeds.

---

Share
Use ← → arrow keys to navigate