System Design · Note 17 of 22
Design a News Feed
Quick answer
How do you design a news feed system?
Store posts once, then build each user's feed either at post time (fan-out on write: push the post id into every follower's cached feed) or at read time (fan-out on read: pull and merge followed accounts' posts). Large systems mix both: push for ordinary accounts, pull for celebrities, merge at read time, and page the result with cursors.
On this page
A news feed is the list of recent posts from the accounts you follow. The design problem is when to do the work of building it: when someone posts, or when someone reads.
Requirements
- Functional: post text/media; follow accounts; see a feed of followed accounts' posts, newest or ranked first; scroll for more.
- Non-functional: the feed loads fast (aim for a few hundred ms); a post may take seconds to appear (eventual consistency is fine); highly available.
- Read-heavy: feeds are read far more often than posts are written.
Capacity estimate
Assumptions: 200 million daily users, each opens the feed 10 times and posts 0.5 times a day, 200 followers on average.
| Quantity | Working | Result |
|---|---|---|
| Feed reads / s | 200 M × 10 ÷ 86,400 | ≈ 23,000 |
| Posts / s | 200 M × 0.5 ÷ 86,400 | ≈ 1,157 |
| Fan-out writes / s | 1,157 × 200 | ≈ 231,000 |
| Feed cache | 200 M × 500 ids × 8 B | 800 GB |
- Fan-out multiplies writes by the follower count; that number drives the whole design.
API
POST /v1/posts {"text": "..."} → 201 {"id": "p9"}
GET /v1/feed?limit=20 → {"posts": [...], "nextCursor": "p18"}
GET /v1/feed?limit=20&cursor=p18 → the next page, older than p18Data model
| Store | Key | Holds |
|---|---|---|
| posts | postId | authorId, body, createdAt |
| follows | (followerId, followeeId) | both directions indexed |
| feed cache | userId | newest ~500 post ids |
| post cache | postId | hydrated post for display |
Fan-out on write (push)
- At post time, a worker copies the post id into each follower's feed cache.
- Read = one cache read. Cost = one write per follower.
Asha publishes p9. With fan-out on write, the work of building feeds happens now, at post time.
Transcript · 6 steps
Fan-out on read (pull)
- At read time, fetch each followee's recent posts and merge.
- Posting is free; reading is slow for users following thousands.
Nothing was precomputed. When Ben opens his feed, the feed service reads who he follows: Asha, Chen, Dev.
Transcript · 5 steps
| Push (on write) | Pull (on read) | |
|---|---|---|
| Read latency | Low | High |
| Write cost | × followers | One write |
| Celebrity post | Millions of writes | Cheap |
| Inactive users | Wasted writes | Nothing wasted |
The hybrid for celebrities
- Push for ordinary accounts; above a follower threshold, store once and pull.
- The reader's feed = cached ids + a few celebrity pulls, merged.
The hybrid: fan out on write for ordinary accounts, but not for celebrities, whose posts would cost millions of writes each.
Transcript · 5 steps
Ranking and pagination
- Ranking: take a few hundred candidates, score them (recency, affinity, engagement), return the top. Plain time order is the baseline.
- Cursor pagination: "older than the last post I saw", never
OFFSET.
Page 1 returns the newest 3 posts, p20, p19, p18, and a cursor naming the last one shown, p18.
Transcript · 4 steps
Bottlenecks and trade-offs
- Fan-out lag: a queue absorbs bursts; posts appear after seconds, not instantly.
- Hot feed caches: shard by user id with consistent hashing.
- Posts table: shard by author; cache hot posts.
- Deletes and unfollows leave stale ids in caches; filter at read time.
Interview questions
- Push or pull? Push for most users, pull for celebrities: the hybrid.
- What goes in the feed cache? Post ids, not bodies, so an edit changes one record.
- Why cursors? Offsets repeat or skip posts as new ones arrive.
- How do you rank? Score a candidate set by recency and engagement; time order is the fallback.
Next: Design a Notification System · Before this: Design a Chat App (WhatsApp)
Common questions
What is fan-out on write?
When someone posts, a worker pushes the post's id into the cached feed of every follower. Reading a feed is then a single fast cache read, but one post costs one write per follower, which is expensive for accounts with millions of followers.
What is fan-out on read?
Nothing is precomputed. When a user opens the feed, the service fetches the recent posts of everyone they follow and merges them by time or rank. Posting is cheap, but every feed load does many queries, which is slow for users who follow thousands of accounts.
How do you handle celebrities with millions of followers?
Use the hybrid model. Accounts above a follower threshold are not fanned out; their posts are stored once and pulled at read time, then merged with the reader's precomputed feed. Writes stay bounded and each read adds only a few lookups.
Why use cursor pagination for a feed instead of offset?
New posts keep arriving at the top, so an offset shifts under the reader and repeats or skips posts. A cursor says continue after the last post I saw, which stays correct as the list changes and uses an index seek instead of skipping rows.
Where are feeds stored?
Usually as short lists of post ids in an in-memory store such as Redis, a few hundred per user, with post bodies fetched separately from a post cache or database. Inactive users' feeds can be dropped and rebuilt on their next visit.