Design News Feed
Design a ranked (Facebook-style) news feed at 2B users. Covers pre-computing ranked feeds every 5 min so reads stay O(1) despite expensive ML ranking, the candidate-vs-ranked feed split in Redis, the feature store for ranking signals, the hide-feedback loop that adapts ranking per user, and the celebrity-bypass hybrid fan-out for the candidate set.
Foundational.
How it works
What are we designing? A ranked news feed — Facebook-style, where the feed is not just chronological but algorithmically ranked by relevance, recency, and engagement signals. Posts can be text, photos, links, or videos. The feed must feel fresh (new posts appear within seconds), personalized (different users see different content), and engaging (ranking optimizes for time-on-site and interactions).
This is the 'design Instagram + ranking' problem. The hard part is no longer the fan-out (we know how to do that); the hard part is pre-computing a ranked feed such that reads are still O(1) even though ranking is expensive (ML model, hundreds of features).
Functional requirements.
- Users post stories (text, photo, link, video).
- Users follow / friend other users.
- The home feed shows a ranked subset of recent stories from friends/pages.
- Users can like, comment, share, hide.
- Feed updates in near-real-time when friends post.
- Feed ranking adapts based on user engagement (hide future similar posts after a hide).
Non-functional requirements.
- Feed read latency: p99 < 200 ms (despite ranking).
- Freshness: a friend's new post appears in the feed within 30 s.
- Personalization: each user's feed is unique.
- Availability: 99.99%.
- Scale: 2B users, 1B+ stories posted/day, 10B+ feed reads/day.
Non-goals. No ad targeting, no marketplace, no stories (24-hour).
Capacity estimation.
Posts. 1B stories/day. Average story ~2KB metadata + media (50% have photos at ~500KB, 5% have video at ~50MB). Metadata = 2TB/day; media = ~3PB/day. Stored on object storage.
Feed reads. 2B users x ~10 feed refreshes/day = 20B feed reads/day = ~230K reads/sec average, peak ~1M/sec.
Fan-out. Average user has ~300 friends and ~50 page follows. 1B stories/day x ~350 followers = 350B fan-out writes/day = 4M writes/sec. This is why we need the celebrity bypass AND a smart pre-computation strategy.
Ranked feed storage. If we pre-compute a ranked feed of 100 story_ids per user, 2B users x 100 x 8 bytes = 1.6 TB. Fits in a sharded Redis cluster.
Ranking compute. If we re-rank a feed of 500 candidate stories on every refresh, each rank call costs ~10 ms on an ML model. To hit 200 ms read latency, we MUST pre-compute ranks, not rank on read.
Bandwidth. 1M reads/sec x 50KB per feed response = 50 GB/s = 400 Gbps. Requires multi-region CDN.
APIs.
POST /v1/stories (text, media_ids, privacy)
GET /v1/feed?cursor=... -> ranked, paginated
POST /v1/stories/:id/like
POST /v1/stories/:id/comment
POST /v1/stories/:id/hide -> trains ranking model (downweight similar)The feed endpoint returns ranked stories. The cursor encodes the user's position in the feed so paginated calls return older stories in rank order (not time order).
Data model.
Stories (sharded by story_id):
stories (story_id BIGINT PK, author_id, type, text, media_url,
created_at, like_count, comment_count, share_count)Feed candidates (per-user, Redis ZSET of recent story_ids):
key: feed_candidates:{user_id}
value: ZSET member=story_id, score=created_at -- raw chronological
capped at 1000 (last ~24h)Ranked feed (per-user, pre-computed, Redis LIST):
key: feed_ranked:{user_id}
value: LIST of ranked story_ids, top 100 pre-computed by the ranker
TTL: 5 minutes -- re-ranked on a scheduleUser features (for ranking, stored in feature store):
user_features (user_id, last_seen_ts, avg_session_length,
affinity_to_author MAP<author_id, float>,
affinity_to_topic MAP<topic, float>, ...)Story features (computed on post):
story_features (story_id, embedding VECTOR, topics LIST<TEXT>,
author_verified BOOL, has_media BOOL, ...)Deep dive: pre-computing the ranked feed.
Ranking is expensive: a modern feed ranker (Facebook's EdgeRank successors, Instagram's) is a gradient-boosted tree or small neural net over ~100 features per (user, story) pair. Scoring 500 candidate stories takes 50-200 ms — too slow for a read that must be < 200 ms total. So we pre-compute.
Pre-computation strategy. A background ranking job runs per user every 5 minutes (or on candidate-list change). It reads the user's feed_candidates ZSET (last 1000 stories), fetches features for each from the feature store, scores them with the ranker model, and writes the top 100 ranked story_ids to feed_ranked:{user_id} with TTL 5 min.
Triggering the ranker. Three triggers:
- Scheduled: every 5 min for active users (last-seen < 1 hour ago). For inactive users, we don't rank — they get a fresh rank on next open.
- On candidate change: when a new story is fanned out to a user, the fan-out worker publishes a
rank_requestevent for that user; the ranker re-ranks. - On read miss: if the user opens the feed and
feed_rankedis missing or expired, the Feed Service calls the Ranker synchronously (the slow path, ~100 ms).
Features. Examples: affinity_to_author (decayed sum of past interactions), story age (decayed by hours), story type (photo/video/link), story's global engagement (a proxy for quality), user's past session length, time of day, device type. These live in a feature store (Tectonic at Facebook, Feast open-source).
The hide feedback loop. When a user hides a story, we publish hide_event to Kafka. A trainer updates user_features.affinity_to_author and affinity_to_topic to downweight that author/topic. The next rank call (within 5 min) reflects the change.
Celebrity bypass. Same as Instagram/Twitter: pages with >10K followers skip fan-out. Their stories are fetched at rank time and added to the candidate pool.
Mixed ranking. Real feeds interleave ranked organic stories with sponsored content (ads) and 'you might like' recommendations. Each slot has a different ranking policy; the feed builder composes them into the final ordered list.
Bottlenecks and failure modes.
-
Ranker overload. 2B users / 5 min = 6.7M rank calls/sec. Each call scores 500 stories. Mitigation: batch rank calls per user (rank 100 stories in one model call); shard the ranker across GPU/CPU pools; skip ranking for inactive users.
-
Feature store latency. The ranker fetches ~100 features per story; for 500 stories that's 50K feature lookups. Mitigation: pre-fetch features into a local cache on the ranker; use a feature store with sub-ms p99 (Redis-backed).
-
Fan-out write amplification. 4M fan-out writes/sec at peak. Mitigation: celebrity bypass; batch fan-out writes per user (one Redis pipeline per follower).
-
Stale feed. Pre-computed feeds are up to 5 min old; a friend's new post may not appear immediately. Mitigation: when a new story is fanned out, prepend it to the user's ranked feed immediately with a 'fresh' flag (the ranker will re-rank it in the next pass).
-
Cold-start users. New users have no engagement history → features are empty → ranking is random. Mitigation: serve a 'popular today' feed for the first week until features accumulate.
-
Model drift. A bad ranking model change can drop engagement 10% in hours. Mitigation: A/B test model changes on 1% of users; auto-rollback if engagement drops.
-
Hide-storm. A controversial post triggers millions of hides simultaneously; the trainer updates features for millions of users. Mitigation: batch updates; throttle the trainer.
Scaling strategy and trade-offs.
Pre-compute vs rank-on-read. We pre-compute for active users (top 100 stories, 5-min TTL). For inactive users (opening the app once a week), we rank on read — the one-time 100 ms latency is acceptable.
Multi-region. Feed cache (Redis) and ranker are per-region. The Stories DB is globally replicated. Ranking compute is heavy; we run rankers in each region to keep user-feature access local.
Feature store. Redis-backed feature store with sub-ms p99. Features are updated by the trainer in batches; reads are eventual (a few seconds behind).
Ranking model. GBDT (e.g. XGBoost / LightGBM) for fast scoring; small neural net for embeddings (text + image). Models are versioned and rolled out via A/B test.
Trade-offs made explicit.
- We chose pre-computation — gained fast reads, lost real-time freshness (mitigated by immediate-prepend of fresh stories).
- We chose per-user ranking — gained personalization, lost computation cost (must run rankers at 6.7M calls/sec).
- We chose 5-min TTL — gained low ranker load, lost adaptivity (hide feedback takes up to 5 min to take effect).
- We chose fan-out-on-write for the candidate set — gained O(1) candidate fetches at rank time, lost write amplification (mitigated by celebrity bypass).
Why does the news feed pre-compute ranked feeds instead of ranking on read?
Pick one answer.
A user hides a story from author X. When will their feed stop showing stories from author X?
Pick one answer.
Engineering mental model
Mental model. Think of Design News Feed as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Design News Feed mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing Design News Feed, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
// Pseudocode
request = receive()
result = design_news_feed(request)
return result
// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: Design News Feed
Change the variables below and predict what breaks first in Design News Feed. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on Design News Feed, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using Design News Feed. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using Design News Feed?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses Design News Feed, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose Design News Feed, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
A useful engineering lens for Design News Feed: define the problem it solves, the simpler design that fails first, the constraint that forces you to introduce this concept, and the new failure modes the concept creates.
Numerical sanity check
Back-of-the-envelope reasoning beats fake precision. State your traffic, payload, concurrency and growth assumptions explicitly, then calculate enough to know whether the current architecture is orders of magnitude away from the target.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
Imagine the simplest version of a system using Design News Feed. What breaks first as traffic grows by 10×, and what would you change before reaching 100×?
Pick one answer.
What you gain, what you pay
- +Pre-computed ranked feeds keep read latency O(1) despite expensive ML ranking.
- +Hide feedback loop adapts ranking per user within ~5 min.
- +Feature store decouples ranking from the data sources (stories, engagement logs).
- +Celebrity bypass in fan-out keeps write amplification bounded.
- −Pre-computation means feeds are up to 5 min stale — fresh posts need immediate-prepend.
- −Ranker compute is heavy — 6.7M rank calls/sec needed for 2B users.
- −Cold-start users have no features — needs a fallback 'popular today' feed.
- −Model drift can drop engagement fast — needs A/B testing and auto-rollback.
How this breaks in production
- Ranker overload at 2B users — needs batching and per-user skip for inactive.
- Feature store latency — needs sub-ms p99 (Redis-backed).
- Fan-out write amplification — needs celebrity bypass.
- Stale feed after a new post — needs immediate-prepend of fresh stories.
- Hide-storm on controversial posts — needs batched, throttled feature updates.
Don't fall into these traps
- •Ranking on read for every feed request — blows the latency budget.
- •Storing the full ranked feed (with story content) instead of just story_ids — wastes cache.
- •Running the ranker synchronously on candidate change — too slow.
- •Single-region feature store — multi-region ranking reads stall on cross-region calls.
- •Skipping the celebrity bypass — fan-out crushes the cache cluster.
Real systems using this
How real systems implement this
- Facebook News Feed — EdgeRank and successors; pre-computed ranked feeds with 5-min TTL; feature store (Tectonic); celebrity bypass. Documented in Meta engineering blog.
- TikTok For You page — Real-time ranking over candidate videos, with a separate exploration pool. Uses a deep neural net over hundreds of features including watch time and re-watch rate.
- YouTube recommendations — Two-stage: candidate generation (collaborative filtering) then ranking (deep NN). Pre-computed per-user recommendations cached in Redis.
Practice saying it out loud
- Q1Design a ranked news feed. How do you keep reads fast when ranking is expensive?
- Q2A user hides a story. When does their feed change?
- Q3How do you handle a new user with no engagement history?
- Q4How do you A/B test a new ranking model safely?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Design Instagram