Design a News Feed: Fan-Out on Write vs Read, and the Celebrity Problem
The news feed is the most asked system design question there is, and it has one genuinely interesting decision in it. Everything else — the API, the storage, the CDN — is scaffolding around the question of when you assemble the feed.
Scope it in thirty seconds
Say what you are building before you build it:
- Users follow other users. A feed shows recent posts from people you follow.
- Reads vastly outnumber writes.
- Freshness matters in seconds, not milliseconds.
- Ranked or purely chronological? Ask. It changes the design.
Then make the read/write asymmetry explicit, because it drives everything: 250M daily actives, 2 posts and 100 feed views per user per day is roughly 5.8k writes/sec against 290k reads/sec — a 50:1 ratio. A design that does work at write time to make reads cheap is obviously right here, and saying so earns the next five minutes.
The actual decision
Fan-out on write (push). When someone posts, immediately write that post's id into the precomputed feed list of every follower. Feeds live in Redis as a capped list per user.
Reads become trivial: fetch one list, hydrate the posts. Single-digit milliseconds. You have moved all the cost to write time, which is exactly what a 50:1 ratio asks for.
Fan-out on read (pull). Store posts once. When a user opens their feed, fetch the people they follow, query recent posts from each, merge and sort.
Writes are trivial. Reads are expensive and get worse the more people you follow.
Where push breaks
A user with 100 million followers posts once. Fan-out on write means 100 million list insertions for a single action. The write takes minutes to propagate, the queue backs up, and ordinary users' posts sit behind a celebrity's in the same pipeline.
This is the heart of the question, and it is why neither pure approach is the answer.
The hybrid
Real systems split by follower count:
- Ordinary accounts (the overwhelming majority) — fan out on write. Their followers' feeds are precomputed.
- Large accounts above some threshold — do not fan out. Their posts stay in one place.
- At read time, take the precomputed feed and merge in recent posts from the large accounts this user follows. That is a handful of extra queries, not thousands.
Now the expensive path runs once per read for a small set of accounts, instead of once per write across millions of followers. Being able to explain why the threshold exists — and that it is tuned, not principled — is the signal the interviewer is looking for.
Pagination that does not duplicate posts
A detail that separates people who have built this from people who have read about it.
Offset pagination (LIMIT 20 OFFSET 40) breaks on a feed, because new posts arrive between page requests and shift everything down. The user sees the same post twice and silently misses others.
Use a cursor: the client sends back the timestamp or id of the last item it saw, and the server returns items strictly older than that. The feed is stable under insertion, and the query is an index seek rather than a scan.
Ranking, if they ask for it
If the feed is ranked rather than chronological, add a scoring stage between retrieval and response, and be clear it is two stages:
- Candidate generation — a few hundred posts from follows, plus some from interest-based sources.
- Scoring — a model ranks them on predicted engagement, recency, affinity with the author, and content type.
Keep the model out of the request path where you can: precompute embeddings and affinity scores, and keep the online step to a cheap ranking pass. Mention that you would need a feature store if features are shared between training and serving, and that training/serving skew is the usual bug.
What interviewers push on
"What happens when someone follows a new account?" Backfill their feed with that account's recent posts, or let it fill naturally. Say which and why.
"How do you cap the feed?" Keep the most recent few hundred ids per user in Redis. Older pages fall through to the database. State the memory maths: 250M users × 500 ids × 8 bytes is roughly 1TB, so sharded Redis, and probably only for active users.
"What if Redis loses a feed?" It must be rebuildable from the posts table. The precomputed feed is a cache, not a source of truth — saying that unprompted is worth a lot.
"Does a deleted post disappear from feeds?" With fan-out on write, the id is already in a million lists. You filter at hydration time rather than trying to remove it from every list.
The shape of a good answer
Estimate, name the read/write asymmetry, choose push because of it, break push with the celebrity case yourself before the interviewer does, land on the hybrid, then go deep wherever they point. Volunteering the flaw in your own design is the single most effective thing you can do in a system design interview — it is what a senior engineer does on a real design review.