~12 min
A news feed's functional list is short — post an update, follow a user, view a feed of updates from everyone you follow — but the design hinges entirely on one decision: does the system compute each user's feed when they post, or when they view? Fan-out-on-write does the work at post time: when a user posts, the system immediately pushes that post into every follower's precomputed feed, so a feed read is just reading a list that's already built. Fan-out-on-read defers the work: a feed read queries every account the user follows and merges the results at request time, so posting is cheap and viewing does the work. Given a target like 500 million DAU and a feed-load SLO of a few hundred milliseconds, the choice is entirely about where you'd rather pay that cost.
Fan-out-on-write's failure mode is the same hot-key problem this course already named for sharding: a user with 50 million followers who posts once triggers 50 million individual feed-list writes, all from a single event, which looks exactly like the hot-shard scenario worked out earlier — a small number of keys (here, a small number of accounts) generating a wildly disproportionate share of write traffic. Fan-out-on-read has no such spike, but it pays a steady cost on every single feed view instead: merging updates from potentially thousands of followed accounts on every read is expensive precisely where the SLO is tightest. The common answer splits the difference by account size: fan-out-on-write for ordinary accounts, where the follower count is small enough that the write fan-out is cheap, and fan-out-on-read (merged in at view time) specifically for the small number of very-high-follower accounts that would otherwise create a hot key.
The data model mirrors the read pattern chosen: a posts table (normalized, one row per post) plus, for fan-out-on-write accounts, a feed_items table keyed by (user_id, post_id) that's exactly what gets read on a feed view — denormalized on purpose, the same trade this course covered when copying data to where it's read pays for itself. That feed_items table is itself a strong sharding candidate, partitioned by user_id the same way any table is once one node can't hold the write volume, since every fan-out write and every feed read is naturally scoped to one user. A cache-aside cache in front of the most-recently-viewed feed pages absorbs the read traffic from users who reload their feed repeatedly in a short window, the same pattern used for the URL shortener's redirect path.
80 million individual feed-list writes from one post — this is the hot-key/hot-shard problem: a small number of accounts generating a wildly disproportionate share of write traffic.