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:
- A personalized feed of posts from friends/followed pages/groups.
- Posts contain text, images, video, links.
- Ranked — most relevant/engaging first, not purely chronological.
- Create posts; like/comment/share; feed reflects engagement.
Non-functional:
- Read-heavy, low latency (< 200 ms to first screen).
- Personalized & fresh — the feed differs per user and updates as new content and engagement arrive.
- Massive scale (billions of users), high availability, eventual consistency.
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
- 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.
- Ranking — score each candidate with an ML model predicting engagement (likelihood of like, comment,
dwell time), weighted by recency and affinity. Sort by score.
- 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
- Ranking compute → bounded candidate sets, precomputed features, cached ranked feeds, dedicated
inference infra.
- Candidate gathering → precomputed timelines (fan-out).
- Feature freshness → streaming feature updates into the feature store.
- 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
- Junior: builds a chronological feed (fan-out) and stops — misses that “news feed” implies ranking.
- Mid: adds a ranking stage, understands candidate generation reuses fan-out, mentions an ML model and
caching.
- Senior: frames the whole thing as the candidate-generation → ranking → assembly pipeline, makes
ranking affordable with bounded candidates + a feature store + result caching, balances freshness vs cost,
and treats integrity/diversity/ads as a distinct assembly stage — while explicitly reusing the fan-out
design for candidates rather than re-deriving it.
Further reading