DEV Community

RONI DAS
RONI DAS

Posted on • Originally published at systemdesign.academy

How Twitter's timeline actually works: the fanout problem

When people first design a Twitter timeline, they write one query: give me the most recent posts from everyone this person follows, sorted by time. It works perfectly in a demo with a hundred users. It falls apart in production, and understanding why is the whole lesson.

The problem is the shape of the graph. Follower counts are wildly uneven. Most accounts follow and are followed by a modest number of people. A small number of accounts have tens of millions of followers. Any design that treats all accounts the same will be wrong for one end of that distribution. This is the fanout problem: when someone posts, how do you get that post into the timelines of everyone who should see it.

There are two base strategies and it is worth being precise about both.

Fanout on read means you build the timeline when the user asks for it. They open the app, and the system gathers recent posts from everyone they follow, merges them by time, and returns the list. Posting is cheap, just one write. Reading is expensive and gets worse the more accounts you follow, because every timeline load is a live gather across many sources. Do this for every user on every refresh and your database spends all its time assembling timelines.

Fanout on write means you build the timeline in advance. The moment someone posts, you push a reference to that post into a precomputed timeline for each of their followers. These timelines usually live in an in memory store, one list per user, so reading is close to instant because the answer is already sitting there. The catch is the write. If an account with forty million followers posts, that one action tries to write into forty million lists. That is a huge, spiky amount of work for a single event, and if a popular account posts often, the system is constantly doing these enormous fanouts.

So the honest answer to "which one" is: both, split by account size. Ordinary accounts use fanout on write. When they post, the system pushes to their followers' precomputed timelines, and those followers get fast reads. High follower accounts are the exception and are deliberately not fanned out. Their posts stay in their own store, and when you load your timeline, the system merges in recent posts from the few big accounts you follow at read time. So a normal timeline load is mostly a fast read of a precomputed list, plus a small live merge for the handful of celebrities you follow. You avoid the impossible write amplification of fanning a celebrity post to tens of millions of lists, and you keep reads fast for everyone else.

A couple of details make this practical. The precomputed timelines do not need to hold every post forever. They hold a bounded window of recent references, often a few hundred, because almost nobody scrolls past that in a session, and older content can be fetched on demand. The timelines store post ids, not full post content, so the list stays small and the actual post text and media are hydrated from a separate store when rendering. That separation keeps the hot timeline data compact and cheap to keep in memory.

There is also the question of ordering. Strict reverse chronological order is simple to reason about, but the modern timeline is ranked, which means posts are scored and reordered rather than shown purely by time. Ranking adds a scoring step on top of the retrieval you just built. The important point for a system design is that retrieval and ranking are separate stages. First you gather the candidate posts using the fanout machinery above, then a ranking layer decides the order. Keeping those two stages distinct is what lets you change ranking without touching how posts are delivered.

How does the real company do it? Twitter's timeline has long used a hybrid fanout model with precomputed timelines held in an in memory store, plus special handling that excludes very high follower accounts from write time fanout and merges them in at read time. On top of retrieval sits a separate ranking layer. The exact internals have changed over the years, but the core shape, precompute for the many and pull live for the few giants, has been remarkably stable.

If you remember one thing, remember that the whole design exists because follower counts are not uniform. A single rule cannot serve both a normal user and an account with tens of millions of followers, so you use two rules and split on account size.

I wrote the full breakdown, with diagrams and the data model, here: https://www.systemdesign.academy/interview/design-twitter

Top comments (0)