Skip to content
Design Twitter/X Feed: The Hardest Feed System at Scale 10 min

Design Twitter/X Feed: The Hardest Feed System at Scale

SD
ScaleDojo
May 11, 2026
10 min read2,449 words
Design Twitter/X Feed: The Hardest Feed System at Scale

The 2013 rebuild that's still taught in interviews today

Twitter's original timeline was computed on demand: open the app, and the system queried every account you followed, pulled their recent tweets, merged everything by timestamp, and rendered it — for every single page load. That works fine at a few thousand users. At hundreds of millions, it means fanning out a live database query across 200+ accounts every time anyone opens the app, and it showed: timeline loads stretched into seconds during peak traffic.

Twitter rebuilt the timeline service around pre-computed caches instead — Raffi Krikorian's team documented the shift publicly in talks around 2013, and it's become one of the most referenced architecture case studies in system design interviews specifically because it demonstrates a principle that generalizes far beyond social feeds: when reads vastly outnumber writes, it's worth paying an expensive write to make every future read close to free. That single trade-off is the spine of this entire design.

Scale, roughly

X (formerly Twitter) stopped publishing detailed official usage numbers after 2022, so any figure below is a public estimate rather than a company-confirmed statistic — worth stating plainly rather than presenting as precise fact.

Metric

Approximate value

Daily posts

~500 million (~5,800/sec average)

Monetizable daily active users (mDAU)

~250 million (Q1 2026 estimate)

Monthly active users

~611 million (Q1 2026 estimate)

Avg. accounts followed per user

~200

Largest follower counts

100M+ (a handful of accounts)

Timeline load target

Sub-200ms, p99

The specific numbers matter less than the shape of the problem they describe: a small number of accounts have follower counts many orders of magnitude larger than everyone else, and that long tail is what breaks the naive version of this design, covered below.

Fanout-on-write: pay at write time, read for free

The core mechanism is called fanout-on-write (also called the push model): instead of computing a timeline when someone opens the app, do the work the moment a tweet is posted, and push it into every follower's pre-built timeline immediately.

Fanout-on-Write (Push Model):

  @user_alice tweets "Hello world!"
       |
  [Tweet Service] -> Store tweet in Tweets DB
       |
  [Fanout Service] -> Get alice's follower list (50,000 followers)
       |
  For EACH follower:
    LPUSH timeline:{follower_id} tweet_id
    (Redis sorted set, score = timestamp)
       |
  50,000 Redis writes per single tweet

  When @user_bob opens app:
  ZREVRANGE timeline:bob 0 49  -> 50 tweet IDs in ONE Redis call
  Multi-GET tweet content from Tweet Cache
  Total: 2 Redis calls, < 10ms

The tweet itself gets written once to a durable store. Separately, a fanout service looks up the author's follower list and writes a reference to that tweet into every one of those followers' timeline caches — typically a Redis sorted set keyed by follower ID, scored by timestamp, so ZREVRANGE returns the most recent items in sorted order with no application-side sorting needed. Loading a timeline becomes two fast Redis operations instead of a live fan-out query across hundreds of accounts.

The trade-off is explicit and worth stating out loud in an interview: one write (posting a tweet) now costs N fanout writes, where N is the follower count. That's a bad trade in the abstract — but reads happen far more often than writes on this kind of platform, often cited around a 100:1 read-to-write ratio, so moving the expensive part to write time and making reads O(1) is a clear net win almost everywhere in the system — except at the extreme end of the follower distribution, which breaks this cleanly.

The celebrity problem, and why the fix is a threshold, not a fixed number

If an account with 100 million followers tweets, fanout-on-write means 100 million Redis writes triggered by one post. At real posting rates, that's enough to overwhelm the fanout service outright — accounts with very large followings have been documented taking noticeably longer for a single tweet to finish propagating through fanout, specifically because of this bottleneck.

The fix is a hybrid fanout model: push for most accounts, and switch to pull (fanout-on-read) once an account's follower count crosses a threshold where the write cost of pushing exceeds the read cost of merging at load time.

Hybrid Fanout:

  User type         Followers       Strategy
  ───────────────   ─────────       ──────────────────────
  Regular user      below threshold Push (fanout-on-write)
  High-follower      above threshold Pull (merge at read time)

  When Bob loads his timeline:
  1. Fetch pre-computed timeline from Redis (pushed tweets)
  2. Fetch latest tweets from high-follower accounts Bob follows (pulled)
  3. Merge and sort by timestamp
  4. Return top 50

  Result: fanout stays bounded regardless of any single account's follower count
  High-follower tweets are merged only for users actively loading their timeline

It's worth being precise about the number here, since it's commonly stated with more confidence than it deserves: public write-ups of Twitter's design (including Krikorian's talk and the widely cited HighScalability summary) generally place the cutoff around 10,000 followers, not a much higher number — the exact figure isn't officially published and is described as tunable against real traffic patterns, not a fixed architectural constant. The right way to think about it in an interview is as a knob you'd tune empirically — set where the marginal cost of one more fanout write exceeds the marginal cost of merging that account's tweets at read time — rather than a specific number to memorize.

The result is bounded fanout: no single tweet, regardless of who posted it, can trigger more than a capped number of writes, and expensive high-follower merges only happen for the users actually loading their timelines at that moment, not for all their followers simultaneously.

Ranking: the timeline stopped being chronological years ago

Everything above explains how tweets get delivered into a candidate pool. It doesn't explain what order they show up in — and by default, "For You" on X isn't reverse-chronological at all; it's a machine-ranked feed, and understanding roughly how that ranking works is now a standard part of this interview question, not an optional extra.

In March 2023, X open-sourced a large portion of its recommendation pipeline on GitHub, including the ranking model then called the Heavy Ranker — a neural network with roughly 48 million parameters, continuously retrained on real engagement data to predict the probability a user will engage with a given post in specific ways (like, reply, retweet, and more). The published pipeline runs in three broad stages:

  1. Candidate sourcing — pull a large pool of possibly-relevant posts from multiple sources: your network (accounts you follow — the fanout mechanism above), plus out-of-network candidates surfaced by other signals (engagement graphs, embeddings, similar users).

  2. Ranking — score every candidate with the Heavy Ranker, weighted toward the engagement types that best predict genuine interest rather than passive consumption. Notably, published weight breakdowns show conversation-style engagement (you reply and the author replies back) weighted on the order of 75–150x higher than a plain like, while negative signals carry outsized penalties — a single block or mute reportedly needs on the order of a hundred-plus likes to offset, and a report needs far more than that.

  3. Heuristics and filtering — apply business rules and safety filters (removing already-seen posts, enforcing content diversity, filtering low-quality or policy-violating content) before the final ordered list goes to the client.

The practical takeaway for a system design answer: fanout is a delivery mechanism that gets candidate posts in front of a ranking system quickly, but a modern feed's actual bottleneck is increasingly the ranking stage, not the delivery stage — you're not just building "get tweets to followers fast," you're building a candidate-generation-and-scoring pipeline where fanout is just the first step.

Snowflake: how tweet IDs get assigned without coordination

One detail that's easy to skip but frequently comes up as a follow-up question: how do you generate a unique ID for every tweet across a distributed fleet of write servers, at thousands of writes per second, without those servers coordinating with each other on every single ID (which would create a bottleneck of its own)?

Twitter's answer, introduced in 2010 and still the standard reference implementation for this problem, is Snowflake: a 64-bit ID made of three parts packed into a single integer.

Bits

Component

Purpose

41 bits

Timestamp

Milliseconds since a custom epoch (Twitter's is Nov 4, 2010) — makes IDs roughly sortable by creation time

10 bits

Machine/worker ID

Up to 1,024 ID-generating nodes can run simultaneously with zero coordination

12 bits

Sequence number

Up to 4,096 unique IDs per millisecond, per machine

Because the timestamp occupies the most significant bits, Snowflake IDs sort naturally by creation time even though they're generated independently across machines — a property a random UUID doesn't give you, and one that matters here because timelines are fundamentally about ordering by time. Across the full 1,024-machine range, the scheme supports well over 4 billion IDs per second in theory, several orders of magnitude beyond what any single service actually needs — the design constraint was avoiding coordination, not raw throughput.

Trending topics face a different constraint than timelines: instead of "get this one post to this one user's feed," it's "count occurrences of every hashtag/topic across the entire firehose of posts, continuously, per region."

Trending Topics Pipeline:

  [All Tweets] -> [Kafka Topic: tweets]
                       |
                  [Flink Stream Processor]
                  Extract hashtags
                  Count in sliding 1-hour window
                  Apply spam/bot filtering
                       |
                  [Top-K Algorithm]
                  Keep top 50 trending per region
                       |
                  [Redis] every 60 seconds
                       |
                  [CDN] cache trending API (TTL: 60s)

  Why streaming (not batch)?
  Batch: compute hourly -> trending is 30 min stale
  Stream: compute continuously -> trending is < 1 min stale

Every post flows through a message queue (Kafka is the typical choice) into a stream processor (commonly Flink) that maintains a sliding-window count per topic — a fixed hourly batch job would leave trending data up to 30 minutes stale, which defeats the point of a "what's happening right now" feature. A streaming pipeline keeps that lag under a minute instead. Spam and bot filtering has to run inline here too, since a coordinated bot network can otherwise trivially force a hashtag to the top of a trending list within minutes.

Failure modes worth knowing

  • Fanout backpressure for high-follower accounts. Even with a hybrid threshold, a burst of high-follower accounts posting simultaneously (a major news event, for instance) can still queue up the fanout service. Rate-limiting and prioritization on that service matter as much as the threshold itself.

  • Deletes and edits don't un-fan-out automatically. A deleted or edited tweet has already been pushed into potentially millions of pre-computed timelines. The read path needs a fast way to check "is this ID still valid" without re-fetching every timeline, usually a lightweight tombstone or deletion-check cache.

  • Thundering herd on cache misses. If a popular account's timeline cache entry expires and thousands of requests hit at once, they can all fall through to the database simultaneously. Standard mitigations (request coalescing, staggered TTLs) apply here just like any other high-traffic cache.

  • Ranking feedback loops. An engagement-optimized ranker can over-amplify content that's good at generating replies specifically (including arguments), not necessarily content users are glad they saw — which is why the published heuristics/filtering stage exists as a check on the raw ranking score, not just an afterthought.

Interview framing

A strong answer sequences like this: "I'd start with fanout-on-write: when a tweet is posted, push its ID into every follower's pre-computed timeline, stored as a Redis sorted set scored by timestamp, so a timeline load is a single ZREVRANGE call instead of a live query across hundreds of accounts. That trade only works because reads vastly outnumber writes. The problem is accounts with very large followings — pushing to millions of followers per tweet doesn't scale — so I'd switch to a hybrid model: push below a follower threshold, and merge that account's tweets in at read time above it, keeping fanout cost bounded regardless of who's posting. On top of delivery, I'd note that a real feed isn't reverse-chronological — it's ranked, typically with a model scoring predicted engagement, with reply-style engagement weighted far higher than a like and heavy penalties for negative signals like blocks or reports. And for ID generation across distributed write nodes without coordination, I'd use a Snowflake-style scheme: timestamp plus worker ID plus per-millisecond sequence number, packed into one sortable integer." That covers delivery, the celebrity edge case, ranking, and ID generation — the four sub-problems interviewers are typically probing for in this question.

Key takeaway

Twitter/X's feed is a study in trading write cost for read speed: fanout-on-write pre-computes timelines so a load is a couple of fast cache calls instead of a live cross-account query, which works because reads vastly outnumber writes. The celebrity problem — a handful of accounts with follower counts orders of magnitude above everyone else — breaks that trade at the extreme end, so a hybrid push/pull model bounds fanout cost regardless of follower count. Beyond delivery, the timeline you actually see is ranked by a model trained on engagement signals, not shown in raw chronological order, and Snowflake-style ID generation lets distributed write nodes assign unique, time-sortable IDs without coordinating with each other. Trending topics are a separate streaming problem entirely, solved with sliding-window counts over a message queue rather than periodic batch jobs. These four patterns — bounded fanout, hybrid push/pull, learned ranking, and coordination-free ID generation — generalize to essentially any large-scale social feed design question.

FAQ

Is Twitter/X's timeline still chronological by default? No. The default "For You" timeline is ranked by a machine learning model trained on predicted engagement, not sorted purely by post time. A separate "Following" tab typically offers a more chronological view of accounts you follow directly.

Why not just always use fanout-on-read (pull) and skip the complexity? Because reads happen far more often than writes on this kind of platform — commonly cited around 100:1 — so computing a fresh timeline on every single page load means redoing the same expensive merge work repeatedly for the same data, whereas fanout-on-write does that work once per tweet and serves it cheaply many times.

What's the exact celebrity follower threshold X uses? It isn't officially published and is generally described as tunable rather than fixed; public discussions of the original design commonly cite a figure around 10,000 followers as the historical starting point, tuned against the point where fanout write cost exceeds read-time merge cost.

Why does Twitter need Snowflake instead of a normal auto-incrementing database ID? A single auto-incrementing counter requires coordination across every write node to avoid collisions, which becomes a bottleneck at high write volume across many machines. Snowflake avoids that by giving each machine its own ID range (via the machine ID and sequence number) so no cross-machine coordination is needed for every single ID.

How is trending topics different from the timeline problem? Timelines are about delivering specific posts to specific followers. Trending topics are a real-time aggregation problem — counting occurrences of terms across the entire platform continuously — which is why it's solved with stream processing over a sliding time window rather than the fanout mechanism used for timelines.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo