You open the app and your feed is there in an instant, assembled from posts by everyone you follow, freshly ranked. Building that feed for one person is easy. Building it for hundreds of millions of people, where some accounts are followed by tens of millions and everyone expects an instant load, is one of the classic hard problems in system design. The whole thing comes down to one decision: when do you do the work of assembling a feed, at write time or at read time.
The core problem
A feed is the merged, ranked list of recent posts from the accounts a user follows. There are two obvious moments to build it. You can build it when someone posts (push the new post into all their followers' feeds), or you can build it when someone opens the app (pull recent posts from everyone they follow and merge). These are fanout on write and fanout on read, and each is great in one situation and terrible in the other.
Key design decisions
Fanout on write: precompute every follower's feed. When a user posts, you immediately insert that post into a precomputed feed list for each of their followers, often held in a fast store like Redis. Reads are then trivial: a user's feed is already sitting there, ready to return. This makes the read path blazing fast, which matters because reads vastly outnumber writes. The cost lands on writes and storage. Every post does work proportional to the follower count, and you store a copy of post references in many feeds.
Fanout on read: assemble the feed on demand. When a user opens the app, you fetch recent posts from each account they follow and merge them. Writes are cheap, because posting is just one insert. Storage is lean, because you are not duplicating anything. The cost lands on reads. Every feed load does real work, and for someone who follows thousands of accounts, that merge is expensive and slow.
The celebrity problem forces a hybrid. Fanout on write breaks on accounts with enormous follower counts. One post from an account followed by twenty million people would trigger twenty million feed writes, a giant spike for a single action. So real systems go hybrid: use fanout on write for normal accounts, and for a small set of very-high-follower accounts, skip the write fanout and instead pull their recent posts in at read time and merge them into the precomputed feed. You get fast reads for the common case and sane writes for the extreme case.
Ranking and freshness
A modern feed is not purely chronological, so after you have the candidate posts you apply ranking, using signals like recency, engagement, and relationship. This is often a separate stage: assembly produces the candidate set (from the precomputed feed plus any celebrity pull), and a ranking service orders it. Keeping assembly and ranking separate lets you change the ranking model without touching how feeds are stored.
How the real systems do it
Meta, Twitter, and Instagram all landed on hybrid fanout for the same reasons. The precomputed feed absorbs the read load for the vast majority of accounts, and the pull-at-read exception handles the accounts whose follower counts would otherwise cause write storms. Feeds are typically capped to a recent window rather than stored forever, because nobody scrolls back a year and unbounded per-user lists get expensive. The storage is usually a fast in-memory layer for the hot feed, backed by durable stores for the posts themselves.
The framing that wins the interview: this is a classic read-heavy versus write-heavy trade-off. Fanout on write pays at write time to make reads cheap. Fanout on read does the opposite. Neither survives the follower-count extremes alone, so you split by account type and take the best of both.
I wrote the full breakdown, with the hybrid fanout diagram and the ranking pipeline, here: https://www.systemdesign.academy/interview/design-meta-news-feed
Top comments (0)