skip to content

In a social network's home timeline, how do fanout-on-write and fanout-on-read differ in where the work happens and what each costs?

level: middleimportance: must knowfreq 72%

answer

  1. which path pays the cost
  2. read-heavy workload ratio
  3. one inbox read vs many lookups
  4. posts times followers
  5. k-way merge at request time

basics

~20 s

Fanout-on-write copies each new post's ID into every follower's precomputed inbox when it is published, so a timeline read is one cheap lookup. Fanout-on-read stores nothing per reader and merges followees' recent posts at request time: cheap writes, expensive reads.

solid answer

~50 s

With **fanout-on-write** (push), publishing a post triggers an async job that appends the post ID to the inbox of every follower, so reading a home timeline is a single range read of one precomputed list. The cost moves to the write path: one post by an author with `F` followers becomes `F` inbox writes, plus storage for every inbox. With **fanout-on-read** (pull), a post is written once to the author's own list, and a timeline read fetches the recent posts of everyone the reader follows and merges them by time, so a user following 300 accounts costs roughly 300 lookups plus a merge on every refresh. Because home timelines are read far more often than posts are written, most designs lean on push for ordinary accounts and pay the write amplification to keep reads fast and predictable.

go deeper

for a junior

Remember the direction of the work: push assembles each reader's list when a post is published, pull assembles it when the reader asks.

for a middle

Explain the mechanics: async fanout workers appending IDs to inboxes, versus a per-request lookup of every followee and a timestamp merge, and what each costs per operation.

for a senior

Show you can reason about tail latency on the pull path and fanout lag on the push path, and name the two extreme users that break each strategy.

for a principal

Frame the choice as moving cost between the frequent and the rare operation, and argue from the read-to-write ratio toward a hybrid rather than a single strategy.

## The problem a home timeline solves A **home timeline** is the list of recent posts from every account a user follows, newest first. The hard part is not storing posts; it is assembling a *personal* list for each reader, where each reader follows a different set of authors. There are two places that assembly can happen: - at **write time**, when an author publishes, or - at **read time**, when a reader opens the app. The two strategies are named for the direction of the work: **fanout-on-write** (also called *push*) and **fanout-on-read** (also called *pull*). ## Fanout-on-write (push) Every user owns a **precomputed inbox**: an ordered list of post IDs that belong in their timeline. When an author publishes: 1. The post is stored once in the post store. 2. A fanout job is enqueued (asynchronously, so the author's request returns quickly). 3. Fanout workers read the author's follower list and append the new post ID to each follower's inbox. Reading a timeline is then a single **range read** of the reader's inbox followed by **hydration**: a batched lookup that turns post IDs into full post content. Costs: - **Write amplification**: one post by an author with `F` followers produces `F` inbox writes. If the average author has 200 followers, every post costs about 200 writes. - **Storage**: one inbox per user, each holding up to N entries. - **Delivery delay**: followers see the post only after the fanout worker reaches their inbox. ## Fanout-on-read (pull) No per-reader list exists. Each author has an **outbox** of their own recent post IDs. When a reader requests their timeline, the service: 1. Loads the reader's follow list. 2. Fetches the recent posts of each followee. 3. Merges those lists by timestamp (a **k-way merge**) and returns the top of the result. Costs: - **Read cost grows with follow count**: a reader following 300 accounts triggers about 300 lookups per refresh. - **Tail latency**: the slowest of those lookups sets the response time, so the timeline's p99 suffers. - **No write amplification**: a post is written once, whatever the audience size, and is visible immediately. ## Side by side | Aspect | Fanout-on-write (push) | Fanout-on-read (pull) | |---|---|---| | Work happens | When a post is published | When a timeline is requested | | Write cost per post | Proportional to follower count | Constant (one write) | | Read cost per timeline | One inbox read plus hydration | One lookup per followee plus a merge | | Freshness | Delayed by fanout lag | Immediate | | Extra storage | One inbox per user | None beyond authors' outboxes | | Worst case | Authors with huge audiences | Readers who follow very many accounts | ## Why read-heavy feeds usually lean on push Home timelines are read far more often than posts are written; an illustrative ratio of 100 timeline reads for every post is common in interview framings. Paying extra on the rare operation (the write) to make the frequent one (the read) cheap and predictable is the classic trade. Push also turns the read path into a bounded operation: one list read regardless of how many accounts the reader follows, which keeps latency flat. The write path, by contrast, is asynchronous, so a few seconds of fanout lag is usually acceptable: the author does not wait, and followers rarely notice. ## Where each strategy breaks - **Push breaks on huge audiences.** An author with tens of millions of followers turns one post into tens of millions of writes, delaying delivery for everyone queued behind it. That failure is what motivates the **hybrid** model: push for ordinary accounts, pull for very high-follower accounts, merged at read time. - **Push wastes work on inactive readers.** Writing into inboxes nobody opens is pure cost, so push systems often skip dormant users. - **Pull breaks on heavy followers and hot read paths.** A reader following thousands of accounts makes each refresh a large scatter-gather. The practical answer in an interview is rarely "pick one": it is to explain both costs, state the read-to-write ratio, and show where the hybrid boundary sits.

  • Why is the fanout step in a push-based timeline usually asynchronous rather than part of the publish request?
    The number of inbox writes is proportional to the author's follower count, which can be thousands or millions. Doing that inline would make publish latency depend on audience size and let one slow inbox write fail the whole request. Enqueuing a fanout job lets the publish return after the single post write, and workers deliver to inboxes in the background, accepting a short fanout lag.
  • Which kind of user is the worst case for a pure fanout-on-read timeline?
    A reader who follows a very large number of accounts. Every refresh must fetch recent posts from each followee and merge them, so the request fans out into thousands of lookups and its latency is set by the slowest one. Push makes that reader cheap, because their inbox is already assembled regardless of follow count.

Push is a newspaper delivered to every subscriber's doorstep at print time; pull is each reader walking to every newsstand they care about whenever they want to read.

saying these in an interview costs you the question

  • Fanout-on-write makes publishing a post a single constant-cost write.
  • Fanout-on-read requires storing a copy of every post per follower.
  • Push is always better because reads become cheap, whatever the audience size.
  • Fanout should run synchronously inside the publish request.
  • Pull timelines have fanout lag before a new post becomes visible.