Question Breakdowns
News Feed
A worked system design: build a home feed of posts from people you follow. The fan-out-on-write vs fan-out-on-read trade-off, handling celebrity accounts, ranking, and pagination.
A news feed shows a user the recent posts from everyone they follow, newest (or most relevant) first. It's the defining social-systems problem because it forces the single most important trade-off in the space: do you do the work when a post is written, or when a feed is read? That one decision — fan-out — shapes everything.
1. Requirements
Functional:
- Users follow others and post content.
- A user's home feed shows recent posts from the people they follow.
- Feed is paginated (infinite scroll).
Non-functional:
- Very read-heavy. Feeds are viewed far more than posts are written.
- Low latency on feed load — it's the first thing users see.
- Scale — hundreds of millions of users, some followed by millions.
- Slight staleness is fine (a post appearing a second late is invisible).
2. The data
The building blocks are simple:
users ( id, name, ... )
follows ( follower_id, followee_id ) -- who follows whom
posts ( id, author_id, body, created_at )The question is never "where do posts live" — it's "how do I assemble one user's feed from the posts of everyone they follow, fast?"
3. The two approaches
Fan-out on read (pull). Build the feed when it's requested: look up everyone the user follows, fetch their recent posts, merge and sort.
- Simple, no precomputation, always fresh.
- But every feed load does a big query across many authors — slow, and repeated for every view. For a user following 1,000 people, that's expensive on every open.
Fan-out on write (push). Do the work when a post is created: push the new post into a precomputed feed/inbox for each follower (often a list in Redis).
- Reads are trivial — a user's feed is already assembled; just read their list. Fast and cheap, which is what you want for the hot path.
- But a write now fans out to every follower's feed — and most feeds are read far more than written, so you've moved work to the cheaper side. This is usually the right default.
push: user posts → for each follower → append to follower's feed list
read feed → read the pre-built list (one cheap lookup)4. The celebrity problem
Pure fan-out-on-write breaks for accounts with millions of followers: one post triggers millions of feed writes — a massive, slow fan-out, and a storage explosion. The standard fix is a hybrid:
- Normal users: fan-out on write (push to followers' feeds).
- Celebrities / huge accounts: fan-out on read (don't push). At feed-read time, merge the user's precomputed feed with a fresh pull of the few high-follower accounts they follow.
So a feed read = "my pushed feed" + "recent posts from the handful of celebrities I follow," merged. This keeps writes bounded (no million-way fan-out) and reads fast (most of the feed is precomputed).
5. Ranking
"Newest first" is the simple version. A ranked feed scores each candidate post (recency, affinity, engagement) and sorts by score. The usual shape: fan-out assembles the candidate set cheaply; a ranking step orders it at read time. Keep the mechanism (how posts reach the feed) separate from the policy (how they're ranked).
6. Pagination
Feeds are infinite, so use cursor pagination (see API Design) — pass an opaque cursor for "older than this," not an offset. It stays correct as new posts arrive at the top and doesn't slow down on deep scrolls.
7. Deep dives
- Feed storage: precomputed feeds are lists of post ids (not full posts) in Redis, capped to the last N — a feed read fetches the ids, then the posts (from cache/DB). Storing ids keeps feeds small.
- Consistency: this is an AP / eventually consistent feature — a new post taking a moment to appear in followers' feeds is fine, which is exactly why fan-out-on-write's async nature is acceptable.
- Fan-out mechanism: the write-time fan-out is async work off a queue, so posting stays instant for the author even when fanning out to many followers.
- Unfollow/privacy: filter at read time, or clean up pushed entries lazily.
What to emphasise
Name the fan-out trade-off, pick push as the default, and handle celebrities with a hybrid:
"It's extremely read-heavy, so I'd do fan-out on write — when you post, I push the post id into each follower's precomputed feed list in Redis, making feed reads a single cheap lookup. The exception is high-follower accounts, where fanning out to millions is too expensive; those I pull at read time and merge into the feed. Fan-out is async off a queue so posting stays instant, pagination is cursor-based, and it's fine for the feed to be eventually consistent."
That's a worked Question Breakdown. The same method — requirements, scale check, the one key trade-off, then deep dives — applies to the rest of this section as it fills in. Jump back to Core Concepts any time.
