System Design: Twitter/X Architecture Deep Dive
How Twitter delivers 500M tweets/day to 300M+ timelines. Covers the fanout problem, hybrid push/pull, real-time search with EarlyBird, and the celebrity tweet challenge.
What you'll learn
- ✓How Twitter solves the fanout problem for 500M tweets per day
- ✓Why celebrity tweets are handled differently (the Lady Gaga problem)
- ✓How EarlyBird enables real-time search across all tweets
- ✓How trending topics are detected in real-time
- ✓How Twitter caches timelines across memcached clusters
Prerequisites
- •Understanding of distributed systems. See [CAP Theorem](/blog/system-design-cap-theorem).
- •Basic knowledge of caching strategies. See [Caching Strategies](/blog/system-design-caching-strategies).
Twitter (now X) processes over 500 million tweets per day. Each tweet must potentially appear in the timelines of millions of followers — in real-time. The core engineering challenge is not storing tweets (that is straightforward) but delivering them: taking a 280-character message and getting it into the right timelines, search indexes, and notification streams within seconds.
Twitter’s architecture has been one of the most publicly discussed systems in tech, in part because its early years were defined by spectacular failures. The “Fail Whale” — Twitter’s error page — became an iconic symbol of a service struggling to keep up with its own growth. The journey from those failures to a system handling 500M+ tweets daily is a masterclass in scaling.
The Tweet Fanout Problem
The fundamental challenge of Twitter is fanout. When a user tweets, that tweet needs to appear in the home timeline of every follower. This seems simple until you look at the numbers.
Consider: a user with 1,000 followers tweets. That is 1,000 timeline updates. Now consider that 500 million tweets are sent per day. If the average tweeter has 200 followers, that is 100 billion timeline delivery operations per day — roughly 1.15 million per second.
The Original Architecture (2006-2010)
Twitter started as a Ruby on Rails monolith backed by MySQL. Timeline generation was pure fanout on read: when you loaded your timeline, the system would query the tweets table for all users you follow and merge the results.
-- Original timeline query (simplified)
SELECT * FROM tweets
WHERE user_id IN (
SELECT followed_id FROM follows WHERE follower_id = ?
)
ORDER BY created_at DESC
LIMIT 200;
This query joins across a massive tweets table and a massive follows table. As Twitter grew, this query became the bottleneck. At peak, the database simply could not keep up, and the Fail Whale appeared.
The Shift to Fanout on Write
Around 2010-2012, Twitter fundamentally redesigned its timeline architecture. Instead of computing timelines at read time, they pre-computed them using fanout on write.
Fanout on Write:
1. User sends tweet
-> Tweet stored in tweets table (single write)
2. Fanout service:
-> Look up all followers of this user
-> For each follower, insert tweet ID into their
timeline cache (Redis sorted set)
3. Follower opens Twitter:
-> Read pre-computed timeline from Redis
-> Single read operation, sub-millisecond
Timeline Cache (Redis Sorted Set):
Key: timeline:{user_id}
Members: tweet_ids, scored by timestamp
Max size: 800 tweets (older ones evicted)
This moved the computational cost from read time to write time. Reading a timeline became a single Redis lookup instead of a complex database join. The tradeoff: every tweet triggers potentially millions of writes to Redis.
The Lady Gaga Problem
Fanout on write works well for normal users. But what happens when Lady Gaga (84M followers) tweets? The fanout service must write her tweet ID into 84 million Redis sorted sets. At even 1 millisecond per write, that takes over 23 hours. By then, the tweet is stale.
This is called the “celebrity problem” or the “Lady Gaga problem,” and it fundamentally shapes Twitter’s architecture.
Hybrid Timeline Architecture
Twitter solves this with a hybrid approach: fanout on write for normal users, fanout on read for celebrities.
Hybrid Timeline Model:
Users are classified:
- Normal users (< ~10,000 followers): Fanout on Write
- High-follower users (> ~10,000 followers): Fanout on Read
When you open your timeline:
1. Fetch pre-computed timeline from Redis
(contains tweets from normal users you follow)
2. Identify high-follower users you follow
(typically 5-50 accounts)
3. Fetch their recent tweets directly
(5-50 point reads, very fast)
4. Merge the two sets
-> Sort by timestamp/relevance
-> Apply ranking model
-> Return top 50 tweets
This caps the write fanout at ~10,000 per tweet
while keeping read latency low (only a few extra queries
for celebrity tweets).
The threshold (around 10,000 followers) was chosen empirically. Below it, fanout on write completes quickly and the write cost is manageable. Above it, the fanout time becomes unacceptable and the per-user read-time query is cheap enough.
Timeline Ranking
Twitter moved from a purely chronological timeline to an algorithmically ranked one. The ranking model scores each tweet based on:
- Engagement signals — predicted likelihood you will like, retweet, or reply
- Recency — newer tweets get a score boost
- Social graph proximity — tweets from people you interact with frequently rank higher
- Content type — the model learns whether you prefer images, threads, or text-only tweets
- Author authority — accounts with consistent engagement get a credibility boost
Real-Time Search: EarlyBird
Twitter search is unique because it must index tweets in real-time. When a breaking news event happens, people expect to search for it within seconds of the first tweet. Traditional search engines like Elasticsearch batch-index documents every few seconds or minutes. Twitter needed something faster.
EarlyBird Architecture
Twitter built EarlyBird, a custom real-time search engine based on a modified Lucene index.
EarlyBird Search Architecture:
Tweet Ingestion:
Tweet posted
-> Kafka event
-> EarlyBird Ingester
-> Indexed in < 10 seconds
Index Structure:
- In-memory inverted index (most recent tweets)
- On-disk segments (older tweets, optimized for reads)
- Partitioned by time: each EarlyBird instance handles
a time range (e.g., "last 7 days" vs "last 30 days")
Search Query Flow:
User searches "earthquake"
-> Query hits multiple EarlyBird partitions in parallel
-> Each partition returns top matches for its time range
-> Root node merges results
-> Ranked by relevance + recency
-> Results returned in < 200ms
Cluster Layout:
- Tier 0 (real-time): last 24 hours, in-memory
- Tier 1 (recent): last 7 days, SSD-backed
- Tier 2 (archive): last 30 days, disk-backed
- Full archive: separate cluster, higher latency
The key innovation is the two-phase index. New tweets go into an in-memory, append-only index that is immediately searchable. Periodically, this in-memory index is flushed to an optimized on-disk segment. This gives both real-time indexing speed and efficient long-term storage.
Search Relevance
Twitter’s search ranking considers:
Search Ranking Signals:
1. Text relevance (TF-IDF variant)
- How well does the tweet match the query?
2. Recency
- Exponential decay: a tweet from 5 minutes ago
scores much higher than one from 5 hours ago
3. Engagement
- Retweet count, like count, reply count
- Weighted by recency (recent engagement matters more)
4. Author quality
- Verified status, follower count, account age
- Penalize accounts flagged as spam
5. Social relevance
- Is the author in your network?
- Did people you follow engage with this tweet?
Trending Topics: Real-Time Detection
Twitter’s trending topics feature must detect emerging topics within minutes of them starting to spike. This is not a batch analytics job — it is a real-time stream processing problem.
How Trending Detection Works
Trending Topics Pipeline:
1. Token Extraction
Every tweet -> Extract hashtags, named entities,
significant n-grams
(Filter out stop words, common phrases)
2. Counting (Apache Heron / Storm)
For each token, maintain a sliding window counter:
- Count in last 5 minutes
- Count in last 1 hour
- Count in last 24 hours
3. Anomaly Detection
For each token, compare current 5-minute count
to expected count (based on historical baseline):
score = (current_count - expected_count) / std_deviation
If score > threshold -> candidate trend
4. Filtering
Remove false positives:
- Common daily patterns ("good morning" spikes at 8am)
- Known recurring events
- Spam clusters (multiple accounts, same text)
5. Localization
Compute trends per geography:
- Global trends
- Country-level trends
- City-level trends
(Same pipeline, different counting partitions)
6. Ranking
Final trend score combines:
- Velocity of growth (how fast is it accelerating?)
- Volume (how many total tweets?)
- Diversity (how many unique users?)
- Geographic spread
The velocity metric is critical. A topic with 50,000 tweets is not trending if it always has 50,000 tweets. A topic that jumped from 100 to 10,000 in 5 minutes is trending. The system detects the rate of change, not the absolute volume.
Caching Architecture
Twitter operates one of the largest memcached deployments in the world. Caching is not an optimization — it is the architecture. Without the cache layer, the database would collapse under read load.
Cache Topology
Twitter's Cache Layers:
Layer 1: CDN (Akamai, Fastly)
-> Static assets, profile images, media
-> Serves ~80% of all HTTP requests
Layer 2: Application-Level Cache (Memcached/Redis)
-> Timeline cache (Redis sorted sets)
-> User object cache (Memcached)
-> Tweet object cache (Memcached)
-> Social graph cache (who follows whom)
Layer 3: Database Read Replicas
-> MySQL read replicas for cache misses
-> Manhattan (custom KV store) for newer workloads
Cache Hit Rates:
- Tweet cache: ~99% hit rate
- User cache: ~98% hit rate
- Timeline cache: ~95% hit rate
Tweet Cache Strategy
Every tweet, once created, is immutable (excluding edits, a recent addition). This makes caching simple — there is no cache invalidation problem for the tweet content itself. Engagement counts (likes, retweets) are stored separately and updated asynchronously.
Tweet Object Cache:
Key: tweet:{tweet_id}
Value: {
id: 1234567890,
user_id: 42,
text: "Hello world",
created_at: "2026-07-12T10:30:00Z",
media_ids: [789, 790],
reply_to: null
}
TTL: None (immutable, evicted only by LRU)
Engagement Counts (separate cache):
Key: counts:{tweet_id}
Value: { likes: 1523, retweets: 342, replies: 89 }
TTL: 30 seconds (frequently updated, eventual consistency OK)
Separating the immutable tweet from its mutable counts means the tweet cache never needs invalidation, while the counts cache can use a short TTL and accept a few seconds of staleness.
Manhattan: Custom Key-Value Store
As Twitter outgrew MySQL for certain workloads, they built Manhattan — a distributed key-value store designed for Twitter’s specific needs.
Why Not Just Use Cassandra?
Twitter evaluated Cassandra, HBase, and others. Manhattan was built because Twitter needed:
- Multi-tenancy — hundreds of services sharing the same cluster without interfering with each other
- Strong consistency option — some workloads (DMs, ads billing) need consistency, while others (timeline cache) do not
- Operational simplicity — a single storage system with tunable consistency rather than operating multiple different databases
Manhattan Architecture:
Storage Engines (pluggable):
- In-memory (fastest, for hot data)
- SSD-backed (balanced)
- HDD-backed (highest capacity)
Consistency Levels:
- Strong: quorum reads/writes (ads, billing)
- Eventual: single-replica reads (timeline, counts)
Data Model:
Key -> Value (opaque bytes)
Supports secondary indexes and range queries
Replication:
- Synchronous within datacenter
- Asynchronous across datacenters
Data Layer Summary
| Workload | Storage | Reason |
|---|---|---|
| Tweets | Manhattan + MySQL | Immutable, high read volume |
| Timelines | Redis (sorted sets) | Pre-computed, ordered by time |
| User profiles | Memcached + MySQL | Cacheable, rarely updated |
| Social graph | FlockDB (custom) + cache | Adjacency list operations |
| Search index | EarlyBird (custom Lucene) | Real-time indexing |
| DMs | Manhattan (strong consistency) | Must not lose messages |
| Analytics | Apache Kafka + HDFS | Event streaming + batch |
| Media | Blob storage + CDN | Large objects, read-heavy |
Technology Stack Summary
Languages: Java (backend services), Scala (some services),
Ruby (legacy), Python (ML/data)
Databases: MySQL (legacy), Manhattan (custom KV store)
Caching: Memcached (objects), Redis (timelines)
Search: EarlyBird (custom real-time search)
Messaging: Apache Kafka
Processing: Apache Heron (real-time), Apache Spark (batch)
Graph: FlockDB (custom social graph store)
CDN: Akamai, Fastly
Monitoring: Custom (Observability team)
Key Takeaways
Twitter’s architecture is shaped almost entirely by one problem — fanout — and the constraints it imposes:
- The fanout problem defines everything. Every architectural decision flows from the question: how do you deliver 500M tweets per day to 300M timelines? The hybrid push/pull model is the answer.
- Celebrities break naive algorithms. Any system with a power-law follower distribution (a few users with millions of followers, most with hundreds) needs special handling for the tail. The Lady Gaga problem is not an edge case — it is a design constraint.
- Real-time search is a different beast. Traditional search engines index in batches. Twitter needed sub-10-second indexing. Building EarlyBird as a custom system was the right call — no off-the-shelf solution met the latency requirement.
- Cache everything immutable aggressively. Tweets do not change (mostly). User profiles rarely change. Caching these with very long TTLs and high hit rates transforms a read-heavy database problem into a memory problem.
- Separate mutable from immutable. Storing tweet content and engagement counts in different caches with different TTLs is a pattern that applies broadly. Do not invalidate a large object because one small field changed.
When you scroll through your Twitter timeline and see tweets from both your friend with 200 followers and a celebrity with 50 million, those two tweets arrived through entirely different infrastructure paths — one pushed into your timeline cache at write time, the other pulled at read time — yet they appear together seamlessly. That convergence is the core architectural achievement.
Related articles
- System Design System Design: Instagram Architecture Deep Dive
How Instagram scaled Django to 2B+ users. Covers feed generation, image processing pipelines, Stories architecture, and PostgreSQL sharding strategies.
- System Design System Design: Netflix Architecture Deep Dive
How Netflix evolved from DVD rental to a global streaming platform serving 250M+ subscribers. Covers microservices, Open Connect CDN, recommendations, and Chaos Engineering.
- System Design System Design: Spotify Architecture Deep Dive
How Spotify streams 100M+ songs to 600M+ users. Covers audio streaming, Discover Weekly ML, the squad/tribe model, event-driven architecture, and offline mode.
- System Design System Design: Uber Architecture Deep Dive
How Uber matches millions of riders with drivers in real-time. Covers geospatial indexing with H3, surge pricing, ETA prediction, and their migration from Python to Go.