system-design

Design a News Feed (Facebook-style)

Difficulty: Tier 2 Asked at: Meta, LinkedIn, Careem, Amazon Time budget: 45–60 min

“Design a news feed” generalizes Twitter and Instagram: a personalized, ranked stream of content from many sources. The feed-building machinery (fan-out) is by now familiar — so this study leans into what a general feed adds: ranking (why it’s not chronological), candidate generation, and the read-time assembly pipeline. Think of it as the feed pattern with a brain.

Prerequisites: Design Twitter, Caching, Recommendation Systems


1. Requirements

Functional:

Non-functional:

Out of scope: the full ML ranking model internals (reference recommendations), ads insertion (mention it).


2. Estimation

Same order of magnitude as Twitter/Instagram: ~2B users, hundreds of thousands of feed loads/sec, billions of posts. The distinguishing cost here is ranking compute at read time — scoring hundreds of candidate posts per feed load, at that request rate, is a major system in its own right.


3. The pipeline: how a ranked feed is assembled

🚨 A ranked feed is a 3-stage pipeline — this framing is the key insight:

flowchart LR
    Load[Feed request] --> CG[1. Candidate generation<br/>gather possible posts]
    CG --> RK[2. Ranking<br/>score each candidate]
    RK --> Filt[3. Filtering & assembly<br/>dedup, ads, diversity]
    Filt --> Render[Rendered feed]

    Sources[(Friends' posts<br/>Pages · Groups<br/>Recommended)] --> CG
    Model[ML ranking model<br/>engagement features] --> RK
  1. Candidate generation — collect posts the user could see: recent posts from friends/followed sources (from precomputed timelines, à la Twitter fan-out) + some recommended content. Produces hundreds–thousands of candidates.
  2. Ranking — score each candidate with an ML model predicting engagement (likelihood of like, comment, dwell time), weighted by recency and affinity. Sort by score.
  3. Filtering & assembly — remove already-seen posts, apply diversity (don’t show 5 posts from one person), inject ads, enforce integrity rules → the final ordered feed.

4. Why ranked, not chronological?

Chronological feeds show everything in order → users miss important posts buried under high-volume sources, and engagement drops. Ranking surfaces the most relevant content first. 🚨 The cost: ranking must run per user, per load, over many candidates — expensive, and the reason this design centers on a read-time scoring pipeline rather than just a precomputed list. State the trade-off: relevance & engagement vs compute cost & complexity (and the “why is my feed out of order / filter-bubble” UX concerns).


5. High-level design

flowchart TB
    Client -->|GET feed| FeedSvc[Feed Service]
    FeedSvc --> CandSvc[Candidate Generation]
    CandSvc --> Timelines[(Precomputed timelines<br/>fan-out, Redis)]
    CandSvc --> Rec[Recommendation service]
    FeedSvc --> RankSvc[Ranking Service<br/>ML model + feature store]
    RankSvc --> Features[(Feature store)]
    FeedSvc --> PostSvc[Post hydration<br/>cache + store]
    PostSvc --> CDN[Media via CDN]

The fan-out layer (Twitter design) feeds candidate generation. The ranking service is the new heavy component. Everything is cached aggressively; features are precomputed in a feature store so ranking is a fast model inference, not a data-gathering exercise.


6. Deep dives

6a. Candidate generation reuses fan-out

Recent posts from your network come from precomputed timelines (fan-out on write + hybrid for high-fan-out sources) — exactly Twitter. 🚨 Say so and move on; the novelty is ranking, not this.

6b. Ranking at scale

Scoring hundreds of candidates per load, millions of loads/sec, needs: a bounded candidate set (rank hundreds, not millions), precomputed features (in a feature store, so inference doesn’t fetch raw data), a fast model served on dedicated inference infra, and caching of ranked results for a short window (a user refreshing within seconds can get a cached ranked feed). Rank lazily — only when the user actually loads the feed.

6c. Freshness vs cost

Users want fresh content and engagement counts, but re-ranking on every scroll is costly. Balance: rank the top of the feed fresh, cache lower pages, and re-rank on refresh or after enough new content arrives. Engagement signals update asynchronously.

6d. Integrity & diversity

Filter spam/misinformation, enforce diversity (author/source variety) so the feed isn’t monotonous, and inject ads at set positions. These are post-ranking assembly rules — a distinct stage from scoring.


7. Bottlenecks & scaling further

  1. Ranking compute → bounded candidate sets, precomputed features, cached ranked feeds, dedicated inference infra.
  2. Candidate gathering → precomputed timelines (fan-out).
  3. Feature freshness → streaming feature updates into the feature store.
  4. Read/media load → caching + CDN (Instagram).

8. Trade-off summary

Decision Chosen Alternative Why
Ordering ML-ranked Chronological Higher engagement/relevance; cost is per-load compute
Candidates Bounded set from fan-out Rank everything Ranking millions/load is infeasible
Features Precomputed feature store Compute at rank time Keeps inference fast
Ranked results Cache briefly Re-rank every scroll Balance freshness vs compute

9. Follow-up questions

Why not just show posts in reverse-chronological order? Chronological ordering breaks down when a user follows many high-volume sources: important posts get buried under a flood of less-relevant recent ones, the user misses what they'd care about, and engagement falls. Ranking predicts what each user is most likely to engage with and surfaces that first, which measurably increases engagement and satisfaction. The cost is significant — you must score many candidate posts per user per feed load with an ML model, making the feed a read-time compute problem rather than a simple list read — plus UX concerns (feeds feel "out of order," filter bubbles). Chronological is simpler and sometimes offered as an option, but ranked is the default because relevance at scale requires it.
How do you rank hundreds of candidates per load at millions of loads/sec affordably? Four levers. First, bound the candidate set — generate a few hundred candidates from precomputed timelines and recommendations, never rank the whole corpus. Second, precompute features in a feature store so ranking is pure model inference, not a data-gathering step that hits many services. Third, serve the model on dedicated, horizontally-scaled inference infrastructure optimized for low-latency scoring. Fourth, cache the ranked result for a short window so a user refreshing within seconds, or paging down, doesn't trigger a full re-rank. Together these turn ranking from "impossible at scale" into a bounded, cacheable inference call.
Where does the fan-out design fit into a ranked feed? It's the candidate-generation layer. The precomputed per-user timelines from fan-out-on-write (with the hybrid pull for high-fan-out sources) supply the recent-posts-from-your-network candidates cheaply, so candidate generation is mostly a fast read of an already-built list plus some recommended content. Ranking then reorders those candidates. So a ranked feed doesn't replace the Twitter design — it sits on top of it, adding scoring and assembly stages after the fan-out has done the gathering.
How do you keep the feed fresh without re-ranking constantly? Rank the top of the feed fresh on load and cache the rest, re-ranking only on an explicit refresh or once enough new content/engagement has accumulated to matter. Engagement signals (likes, comments) flow into the feature store asynchronously via streaming, so the model sees reasonably fresh features without you recomputing the whole feed per event. This bounds compute while still feeling live — the parts users notice (the top, and refreshes) are fresh, and the expensive full re-rank happens only when it's worth it.

10. What junior / mid / senior answers look like


Further reading