Production-grade Twitter/X architecture built progressively across 6 stages: durable tweet write path, social graph, hybrid push/pull home-timeline fanout, ranking and search, engagement/notifications/moderation, and ads plus analytics — 25 components at the final stage, every stage sized for >2× headroom at 300K rps across 3 AZs. A teaching design inspired by Twitter's published engineering, not its internal architecture.
Start with the core domain: create tweets, fetch tweet details, and model tweet lifecycle correctly.
What was missing: Everything — start with the core loop: post a tweet durably and read it back fast.
Why that's risky: Tweet DB sharding is by tweet id, so 'all tweets by author X' is a scatter-gather until an author index exists — acceptable while there is no timeline yet, and fixed in Stage 3.
What gets added: Edge: a global Media CDN for images/video (origin: Media Storage) and an L7 load balancer tier in front of an API gateway that authenticates, rate-limits and routes. Core: a stateless Tweet Service that assigns Snowflake ids and writes to a sharded, 3-way replicated Tweet DB before acknowledging, with a Tweet Cache in front because 97% of traffic is reads.
Trade-offs: Cache-aside reads mean a brief window where a just-deleted tweet can still be served from cache; deletes invalidate the key and the TTL bounds staleness. Media never flows through the API tier — clients upload with pre-signed URLs and download from the CDN.
Add the social graph and the read models needed for user profile timelines and follow relationships.
What was missing: The social graph — who follows whom — which every later feature (timelines, notifications, recommendations) depends on.
Why that's risky: Celebrity follower lists (tens of millions of ids) are hot and huge; they are paged and never loaded whole, otherwise one account can pin a cache shard.
What gets added: A User Service for profiles, follow/unfollow and profile timelines, backed by a Social Graph DB (forward and reverse edge tables, sharded by user id) and a Social Graph Cache holding hot profiles and adjacency lists.
Trade-offs: Storing both edge directions doubles write cost for follow/unfollow but makes both 'who do I follow' and 'who follows me' single-shard reads — the right trade for a read-dominated graph.
Build the core read-heavy home timeline and handle the hardest product problem: celebrity fanout.
What was missing: The hardest problem in this system: turning tweets plus the follow graph into a home timeline at 165K+ reads/s, including celebrity accounts.
Why that's risky: Fanout lag is the key SLO: if consumers fall behind, timelines go stale for everyone. Consumer lag drives autoscaling and alerting.
What gets added: A Timeline Service (home mixer), a Timeline Cache of precomputed tweet-id lists per active user, a replicated Kafka event log fed through a transactional outbox, and a Fanout Worker that pushes each new tweet id into followers' timelines. Accounts above 100K followers are not fanned out — their tweets are merged in at read time (hybrid push/pull).
Trade-offs: Fanout is asynchronous and eventually consistent: a new tweet reaches followers' timelines within seconds, not instantly. Write amplification (one tweet → up to 100K timeline inserts) is paid off the request path so posting stays fast.
Evolve from a recency feed into a ranked social platform with search and trending systems.
What was missing: Relevance and discovery: a reverse-chronological feed and no way to find tweets by keyword.
Why that's risky: Ranking is on the hottest path, so it must be the first thing to shed: on deadline or error the mixer serves reverse-chronological instead of failing the request.
What gets added: A Ranking Service that scores timeline candidates with an in-memory model under a 150ms deadline, a Search Service over a time-partitioned Search Index fed by an indexing consumer on the event log (tombstones for deletes), with results hydrated from the Tweet Cache. Trends are computed from the same event stream.
Trade-offs: Ranking adds ~20ms to 80% of timeline reads ('For You'); 'Following' skips it. Search is near-real-time (5s refresh), not transactional.
Add the major asynchronous product workloads that make the platform feel alive and safe.
What was missing: Engagement (likes, retweets, counts), notifications and safety — the loops that make the product social and keep it usable.
Why that's risky: A viral tweet produces a like storm on one key; per-shard counter buckets spread it. Notification bursts are coalesced ('and 499 others') so one viral post doesn't page millions of devices.
What gets added: An Engagement Service over a wide-column Engagement Store with sharded counters, a Notification Service consuming engagement/mention/follow events and delivering through APNs/FCM, and a Moderation Worker that classifies every new tweet and writes policy labels back to Tweet DB. Conversations reuse tweets (replies carry a parent id).
Trade-offs: Counters are eventually consistent (aggregated, then refreshed into the Tweet Cache) — exact like counts in real time would turn every viral tweet into a single hot row.
Finish with the platform view: monetization, analytics, model training, multi-region control, and safe operations.
What was missing: Monetisation and the data loop that measures and improves the product.
Why that's risky: Ad selection quality is its own ML system; here it is correctly scoped as a bounded dependency. Multi-region active-active, observability and backup tooling are named, not drawn.
What gets added: An Ad Service that fills the timeline's ad slot from an in-memory ad index under an 80ms hard deadline (drop the slot on timeout), and an Analytics Lake fed by its own consumer group with impressions, engagement and experiment exposures for KPIs, A/B analysis and model training.
Trade-offs: Ads are best-effort by design: a slow or failing Ad Service costs revenue for that request, never timeline latency or availability.
Use a hybrid approach. Precompute timelines for normal users where follower counts are manageable; switch celebrities and extreme hot accounts to fanout-on-read or partial materialization to avoid explosive write amplification.
Use tombstones in the tweet store and publish delete events to all downstream consumers. Timeline caches, search indexes, conversation graphs, and analytics readers must interpret deletes idempotently.
Separate candidate generation from ranking. Use a candidate timeline store, cache hydrated tweets, maintain an online feature store, and degrade to recency or lightweight ranking when feature systems are slow.
Write interaction events to a stream, aggregate asynchronously, and store eventually consistent counters separately from tweet objects. Keep UI tolerant to lagging counts and dedupe interaction events by user/tweet/action.
Profile timelines are author-centric and easy to partition by author/time, while home timelines are user-specific and require graph joins, fanout, and ranking. Keeping them separate avoids mixing two very different read patterns.
Compute trends from the engagement stream asynchronously using windowed aggregations by region/topic. Serve trends from precomputed stores and let search or trends APIs degrade independently from core timeline reads.
Keep ad selection separate from organic feed computation. Inject sponsored candidates during ranking with pacing, campaign targeting, policy rules, and strict latency budgets; fall back gracefully if ad systems are unavailable.
Keep the tweet write path minimal and durable, then fan out events asynchronously. Downstream systems should consume independently with retries and DLQs; the platform should degrade by disabling enrichments rather than blocking core posting.
You're in the middle of an interview session. Leaving now will end your current attempt.
Explore concept overviews, real-system examples, key tradeoffs, and interview talking points for each roadmap section.
You've conquered this phase. These are the skills you now own: