Skip to content
Laviyx Learn

Try

System Design course menu

System Design: News Feed Like Instagram or X

Design a social news feed: fan-out on write and on read, the celebrity problem, a hybrid approach, feed caching, ranking, pagination, and media storage.

Advanced6 min readUpdated
On this page

The heart of this question is one choice: do you do the work when someone posts, or when someone reads?

1. Requirements#

Functional: create posts, follow users, and see a feed of posts from people you follow.

Non-functional: feed loads in under about 300 ms, eventual consistency is acceptable, and availability matters more than exact order.

2. Estimates#

Python
daily_users = 300_000_000
feed_loads = 10
posts_per_day = 100_000_000
avg_followers = 300

print(f"Feed reads: {daily_users * feed_loads / 86_400:,.0f}/s")
print(f"Posts:      {posts_per_day / 86_400:,.0f}/s")
print(f"Feed inserts if every post is copied: {posts_per_day * avg_followers / 86_400:,.0f}/s")
Output
Feed reads: 34,722/s
Posts:      1,157/s
Feed inserts if every post is copied: 347,222/s

Reads dominate posts, and copying posts to followers produces an enormous number of writes.

3. Data model#

Text
users(id, name)
follows(follower_id, followee_id)
posts(id, author_id, text, media_key, created_at)
feed_cache: user_id --> [post ids, newest first]

4. Fan-out on read#

Build the feed when it is requested: find who the user follows, fetch their latest posts, and merge them.

  • Pro: posting is instant, and nothing is wasted on inactive users.
  • Con: reading is slow, because it may touch hundreds of accounts.

5. Fan-out on write#

Prepare each feed in advance. When someone posts, add the post's ID to each follower's feed in Redis. Reading is then a simple lookup.

  • Pro: feeds load very fast.
  • Con: posting is expensive for accounts with many followers.

6. The celebrity problem#

An account with 100 million followers would cause 100 million writes per post. The answer is a hybrid: fan out on write for normal users, and merge celebrities' posts at read time.

Python
import heapq

feeds = {"asha": []}
follows = {"asha": ["ravi", "meena", "star"]}
celebrities = {"star"}
posts_by = {"star": [(106, "star: new film"), (101, "star: hello")]}


def publish(author, post_id, text):
    if author in celebrities:
        posts_by.setdefault(author, []).insert(0, (post_id, f"{author}: {text}"))
        return
    for user, followed in follows.items():
        if author in followed:
            feeds[user].insert(0, (post_id, f"{author}: {text}"))


publish("meena", 103, "new job")
publish("ravi", 105, "lunch")


def read_feed(user, limit=4):
    lists = [feeds[user]]
    lists += [posts_by.get(a, []) for a in follows[user] if a in celebrities]
    merged = heapq.merge(*lists, key=lambda p: -p[0])
    return [text for _, text in list(merged)[:limit]]


for line in read_feed("asha"):
    print(line)
Output
star: new film
ravi: lunch
meena: new job
star: hello

The pre-built feed and the celebrity's posts are merged at read time, in order.

7. High-level design#

Text
Post --> Post service --> Posts DB
              |
              v
          Fan-out queue --> Workers --> Feed cache (Redis)

Read --> Feed service --> Feed cache --> merge celebrities
              |
              v
         Hydrate: fetch post, author and like counts (cached)

Queues keep posting fast, because workers do the fan-out in the background. Skip inactive users, to save work and memory, and build their feed when they return.

Only IDs go in the feed. The feed service then looks up the post details, which keeps memory small, and means that an edited post is correct everywhere.

8. Ranking#

Modern feeds are not simply newest-first. A system picks candidates, scores them, and sorts them. A simple score might combine engagement and age:

Python
def score(likes, comments, hours_old):
    return (likes + 3 * comments) / (hours_old + 2) ** 1.5


posts = {"Old viral post": (900, 80, 24), "Fresh post": (20, 5, 1), "Recent post": (100, 10, 5)}
ranked = sorted(posts, key=lambda p: score(*posts[p]), reverse=True)
for name in ranked:
    print(f"{score(*posts[name]):6.1f}  {name}")
Output
   8.6  Old viral post
   7.0  Recent post
   6.7  Fresh post

Real systems use machine learning models, but the structure is the same: find candidates, then rank them.

9. Pagination and media#

Use cursors rather than offsets, because the feed changes constantly. Keep images and video in object storage, behind a CDN.

Trade-offs to mention#

ChoiceBenefitCost
Fan-out on writeFast readsHeavy writes, wasted work
Fan-out on readSimple writesSlow reads
HybridBothMore complex

Key takeaway#

Next: Design a Video Platform.

Finished this lesson?

Some links are affiliate links. If you buy through them, Laviyx Learn may earn a commission at no extra cost to you. As an Amazon Associate, we earn from qualifying purchases.