System Design Case Study
News feed
You open Instagram or Facebook on the couch, pull to refresh, and a ranked mix of friends, pages, and suggestions appears in under a second. It feels like a timeline. It is really a retrieval + ranking product with privacy guards.
A news feed is not posts sorted by time. It chooses candidates, filters private or blocked content, ranks what matters, then posts fast, and logs what you actually saw.
Open feed journey
Friends, recs, ads within a budget.
Blocks, deletes, privacy, policy.
Score, then diversity and inventory.
Objects to client; impressions async.
Try it: news feed assemble and rank
The feed mixes followed publishers, ads, and ranking features. Assembly should be cacheable per user segment where possible.
- Client
- Feed API
- Candidate service
- Ranker
- Cache
- Assemblies
- 0
- Cache hits
- 0
- Mode
- cold
- Path hop
- 0
Candidates
fan-in0 assemblies.
Cache
TTL0 warm hits.
Freshness
rankBreaking posts may bypass cache for a short window.
Open a cold feed assembly, then a warm cached feed for the same user.
Scope boundary: ranked discovery, not only timeline delivery
Social microblog lesson
Optimizes author-to-follower delivery: post durability, , celebrity hot partitions, timeline freshness, and cross-device consistency.
Read the microblog design →This news-feed lesson
Optimizes discovery quality after delivery: multi-source candidates, eligibility, ranking, diversity, experiments, impression truth, and safe model rollback.
What actually happens
On read, the feed service loads ids from a (and other sources), runs filters, scores with , applies a , then a page with a . An records exposure asynchronously.
On write, posts land in durable storage. Delivery into timelines may use so celebrities do not melt push paths, but ranking quality is a separate loop: features, models, canaries, and holdbacks.
At Facebook-scale numbers (billions of users, hundreds of millions of posts/day), you must bound candidate budgets or online scoring cost explodes.
How to choose the design moves
1. Is the hard problem delivery or discovery? Pure follow-graph timelines lean on fan-out. Personalized discovery needs + .
2. Can ranking override privacy? Never. is a hard gate before and after scoring.
3. Will page 2 duplicate page 1? Ranked feeds reorder; use a and a truthful for learning.
Simple rule of thumb
Bound candidates, filter eligibility, spend rank budget wisely, hydrate with a final privacy check, log exposures honestly. If the ranker dies, serve chronological or cached candidates, never an empty private leak.
Case-study upgrade
News Feed Ranking Math
A news feed combines candidate generation, filtering, ranking, hydration, and impression logging. Correctness includes privacy and deletion, not only ranking.
Assumptions and formulas
- Daily active users: 1B. Refreshes/user/day: 10. Posts/day: 500M.
- Feed cache stores candidate ids; online ranking should score a bounded candidate set.
- Visibility filtering rechecks deleted, private, blocked, and muted content at read time.
Concrete math
- Feed reads: 1B x 10/day = 10B/day = 115.7K QPS average; peak can reach 350K to 1M QPS.
- Posts: 500M/day = 5.8K/sec average; peak can be 20K to 60K/sec.
- Fan-out: 5.8K/sec x 500 followers average = 2.9M timeline inserts/sec.
- Feed cache: 1B users x 1,000 post ids x 8 bytes = 8 TB raw; with overhead plan tens of TB.
- Ranking: 100 candidates/read x 350K peak QPS = 35M candidate scores/sec if fully online.
Design decisions forced by numbers
- Pre-rank and cache candidates; online rank only the top bounded set.
- Over-fetch candidates because filtering removes deleted or private items.
- Use stable cursors so inserts and ranking changes do not duplicate or skip too much.
Scaling to millions
- At 1M users: chronological feed cache is enough.
- At 10M users: add fan-out workers, social graph cache, and media hydration cache.
- At 100M+ users: add ranking pipeline, hybrid fan-out, visibility recheck, stable cursors, and degraded cached feed.
Readable flow
Interview follow-ups to expect
- Where are privacy and deletion enforced?
- How much ranking can happen online?
- What happens when ranking features are stale?
Operational readiness checklist
After the math, explain how this capacity plan is measured, protected, launched, and evolved.
Observability
- Attach each capacity estimate to a dashboard metric: p99 latency, queue age, cache hit rate, shard skew, error rate, and freshness lag.
- Alert on rate-of-change and saturation, not only hard failures; backlogs and hot keys usually warn before an outage.
Security and abuse
- Budget for auth checks, rate limits, quota isolation, audit logging, privacy filters, and abuse-review side paths.
- Separate trusted internal events from user-controlled input so retries and backfills cannot bypass policy checks.
Degraded modes
- Define the fallback when a dependency is slow: stale cache, partial results, read-only mode, delayed async work, or admission control.
- Protect the invariant first; reduce freshness, personalization, or analytics quality before risking duplicate or corrupt state.
Testing and rollout
- Test average, peak, and hot-object traffic; include retry storms, cold caches, lagging workers, and regional dependency loss.
- Use canaries, shadow reads, dual-write validation, feature flags, and explicit rollback criteria for risky path changes.
Rollout, backfill, and runbooks
- Make migrations and backfills idempotent, resumable, rate-limited, and visible through progress and error metrics.
- Write the runbook before launch: owner, dashboards, paging thresholds, mitigation switches, replay steps, and repair commands.
10x evolution
- For news feed ranking math, state which number forces the next move: cache memory, shard count, write amplification, queue lag, egress, or failover reserve.
- Add the next layer only when the metric forces it: sharding, regional reads, async replay, hot-key isolation, or stricter backpressure.
Scope you should nail down
Product surface
A reader should receive a page of posts from followed accounts and selected recommendations. Posts can contain text, images, or video, while likes, comments, and shares create feedback for future ranking. Following changes which authors are eligible; it does not guarantee that every post appears on the first page.
Define what refresh means before choosing a cache policy. An explicit refresh may generate a new ranked session, whereas scrolling should continue the existing session without repeating posts. A new-post notification can invite a refresh without moving content while the reader is scrolling.
Scale targets
Use the following as a hypothetical workload: two billion registered users, one billion daily active users, and 500 million posts per day. These are sizing assumptions for the exercise, not measurements of a particular company. Assume a 200 ms server-side p99 target and evaluate network and media download latency separately.
Stale like counts are usually tolerable for a short period. A deleted post or newly private account has a stricter visibility requirement: a fast ranker cannot make stale authorization acceptable. Celebrity accounts also create highly uneven delivery work, so average followers alone cannot size fan-out workers.
Capacity picture
Feed requests: 1B DAU × 10 refreshes ≈ 115K QPS avg; peak 350K–1M
Posts: 500M/day ≈ 5.8K/sec; peak 20K–60K/sec
Fan-out pressure: 5.8K/sec × 500 followers ≈ 2.9M timeline inserts/sec → async
Feed cache: 1B × 1,000 ids × 8B = 8TB raw before sorted-set overhead
Ranking load: 100 candidates × 350K QPS = 35M scores/sec if fully online: pre-rank
Social graph: 2B × 500 friends × 100B ≈ 100TB
Feed read pipeline
Read the diagram definition
sequenceDiagram
autonumber
participant U as User
participant F as Feed service
participant C as Candidate cache
participant G as Graph filter
participant R as Ranker
participant H as Hydration cache
participant I as Impression log
U->>F: getFeed(cursor)
F->>C: load candidate post ids
F->>G: remove blocked/private/deleted
F->>R: score top 100
R->>H: batch hydrate posts + authors
H-->>F: page objects
F-->>U: feed page + stable cursor
F-->>I: impression events (async)Candidates, ranking, and the learning loop
Separate retrieval from ranking. Retrieval protects recall; ranking spends a bounded latency budget; the impression log records what was eligible and shown so offline training does not learn from false exposure.
Read the diagram definition
flowchart LR
A[Friend and group posts] --> D[Candidate union]
B[Recommendations] --> D
C[Eligible ads] --> D
D --> E[Policy and privacy filter]
E --> F[Lightweight pre-ranker]
F --> G[Heavy ranker]
G --> H[Diversity and inventory mixer]
H --> I[Hydrate and recheck visibility]
I --> J[Serve ranked page]
J -. impression, dwell, hide .-> K[Feedback log]
K -. offline training .-> L[Versioned model]
L -. canary rollout .-> G
M[Delete or privacy event] -. invalidate .-> D
M -. final guard .-> IBound the candidate budget
Suppose retrieval returns 600 friend posts, 250 recommendations, and 150 advertisements. Deduplicate those 1,000 candidates and remove ineligible items before a cheap pre-ranker selects 200 for the expensive model. The final mixer chooses a 50-item page, leaving enough extra candidates to replace items rejected by the last visibility check.
This arrangement separates recall from precision. Retrieval must find worthwhile posts at all; ranking cannot recover a post that was never retrieved. Scoring 200 instead of 1,000 candidates reduces model invocations fivefold, but an overly aggressive pre-ranker can remove the very posts the expensive model would have preferred. Measure candidate coverage alongside serving latency.
Make exposure logs truthful
An impression means the client actually displayed a post under an agreed viewability rule, such as a minimum visible area and duration. Returning a post from the server is only a delivery event: the user might close the app before scrolling to it. Assign an exposure identifier and log the model version, experiment, and displayed position when the client confirms the impression.
Join a later like or hide to that exposure identifier and deduplicate retried client events. Otherwise the training data can mark unseen posts as ignored, or count one interaction twice. Keep privacy-sensitive identifiers restricted and define retention for raw exposure data.
Experiment with guardrails
Consistent assignment, ramp 1% → 5% → 25% → 50%, concurrent holdback. Auto-stop on p99, crashes, hides/reports, diversity, or empty-feed regressions, even if clicks rise.
Correctness invariant
No ranking score may override . Deletion, block, membership, age, regional policy, and privacy run before ranking where possible and again immediately before the response.
FAANG-level hardening
Capacity and SLOs
500M posts/day ≈ 5.8K writes/sec; ×500 followers ≈ 2.9M timeline inserts/sec. Target feed p99 under 200ms and freshness lag under 60s for normal follows.
Metrics and degraded modes
Watch fan-out lag, ranking p99, candidate fill, visibility rejects, cursor replay errors, cache hit rate, impression lag. If ranker fails, serve cached or chronological with privacy intact.
Security and privacy
Never trust cached candidates blindly. Recheck deletion, blocks, membership, private visibility, and regional policy before hydration. Moderation must invalidate feed caches.
Rollout and 10x
Shadow feeds, canary ranking with holdbacks, backfill after graph changes. At 10x: regional shards, pre-ranked pools, privacy invalidation fan-out.
Hard-part drill: stable ranked cursors
Suppose page one returns posts A through T. A new ranking run moves A below T before page two arrives; simply asking for scores below the last score can repeat A or skip an unseen post. Create a ranked session with a stable ordered candidate list, retain it for a bounded lifetime, and return an opaque cursor containing its session identifier and next position.
Recheck current visibility for every subsequent page and skip removed items. A model version or last post identifier alone cannot reconstruct an order if candidate membership and scores changed. If the session expires, explicitly start a fresh feed or use a documented best-effort deduplication policy. Sign or validate cursor contents so clients cannot change another user’s session.
APIs worth sketching
getFeed(user_id, cursor?, limit?)Post[] + stable cursor
createPost(user_id, content, media_ids?, visibility?)Post
likePost(user_id, post_id)Like count updated
commentPost(user_id, post_id, content)Comment
followUser / unfollowUserGraph edge changes
Core data model
users
PK id
username, avatar_url, bio
followers_count, following_count
created_atposts
PK id
user_id, content
media_ids JSON
likes_count, comments_count, shares_count
visibility (public, friends)
created_atfriendships
follower_id, followee_id
created_at
UQ (follower_id, followee_id)likes
user_id, post_id
created_at
UQ (user_id, post_id)comments
PK id
post_id, user_id, content
parent_id (nullable)
created_atfeed_cache
# in-memory sorted-set sketch per user timeline
key: "feed:{user_id}"
score: rank_score # ML score or epoch ms
member: post_id
policy: keep latest ~1000 (trim tail)High-level architecture
Feed generation (delivery layer)
Pull (fan-out on read)
For fan-out on read, store a post once and fetch recent posts from followed authors when their follower opens the feed. If a user follows 1,000 accounts, issuing 1,000 independent reads for each refresh is expensive and exposes the page to the slowest dependency. Batch requests, cap candidates per author, and merge bounded result sets. This favors authors with large audiences who post infrequently, because inactive followers generate no delivery work.
Push (fan-out on write)
For fan-out on write, a worker inserts the new post identifier into each follower’s candidate list after the post is durably stored. Reads then begin from one prepared list rather than querying every author. The cost moves to the write path: one post with ten million followers can produce ten million inserts. Queue the work, make each insert idempotent, and expose the resulting freshness lag instead of delaying the author’s acknowledgement until every follower is updated.
Push for normal users; pull/merge for celebrities. Merge cached feed + live celebrity posts on read.
Hybrid is key for delivery: avoid writing to millions of timelines when a celebrity posts. Ranking still runs after candidates are gathered.
// On post creation
if author.followers_count > 10000:
# Celebrity: no fan-out
store in post DB only
else:
# Normal: fan-out to followers
for follower in get_followers(author_id):
cacheStore.zadd(f"feed:{follower}", {post_id: score})
// On feed read
cached = cacheStore.zrevrange("feed:{user}", 0, limit)
celebrity_posts = pull_from_followed_celebrities(user_id)
merged = merge_and_rank(cached, celebrity_posts)Feed ranking
ML ranking model
Chronological is naive. Rank by predicted engagement: P(like), P(comment), P(share), plus recency decay and content diversity.
Features
Recency expresses how quickly a post becomes less useful with age; relationship strength captures repeated meaningful interaction with its author. Content type and past clicks estimate what the reader may prefer, while engagement rate must account for how many people actually saw the post. A post with 100 likes after 200 impressions provides a different signal from 100 likes after a million impressions.
Features also have a freshness and retrieval cost. Batch-load shared author and post features, cache slowly changing features, and specify defaults for missing values. Experiment with the objective carefully: maximizing clicks alone may favor sensational content, so include user satisfaction, negative feedback, and diversity constraints.
Avoid ten consecutive posts from one author. Interleave types. Use MMR-style diversity.
Feed storage
Key feed:{user_id}, score = rank or time, member = post_id. ZREVRANGE for top N; trim to ~1000 items.
Older pages fetch from durable stores with cursor pagination, not endless cache growth.
ZADD feed:user_123 0.95 post_456
ZADD feed:user_123 0.87 post_789
ZREVRANGE feed:user_123 0 49
ZREMRANGEBYRANK feed:user_123 0 -1001Social graph
Adjacency list
Store follower/followee edges in SQL or a graph DB for friend-of-friend queries.
Cached follower sets
followers:{user_id} as a set for fan-out. Shard by user_id at scale.
Media processing
Store uploaded media in object storage and return a media identifier to the post service. Processing workers generate image sizes and video streaming renditions asynchronously, then publish their availability. The post can show a processing state until the minimum required rendition is ready.
Deliver the selected rendition through a CDN so scrolling through a feed does not send every byte through feed servers. Hydration should return metadata and authorized media references, not fetch large video bodies. Private media requires access control at the delivery layer as well as on the post itself.
Real-time updates
Long polling
Client asks "any new posts?" Server holds until data or timeout. Simpler than WebSocket.
WebSocket
Push when a friend posts. Low latency; scale connections regionally.
Practical pattern
Post created → stream event → notify path. Or refresh on focus with an "X new posts" banner.
Bottlenecks to call out
Celebrity fan-out
Hybrid push/pull; never full push for mega accounts.
Feed read latency
Pre-compute candidates; bound celebrity merge; cache.
Hot user feed
Replicas and CDN for static; protect origin reads.
Ranking latency
Pre-score, cache scores, batch inference, pre-rankers.
Takeaway
- Discovery: candidates → eligibility → rank → mix → hydrate
- Delivery: hybrid fan-out; celebrity pull/merge
- Learning: truthful impressions; canary with holdbacks
- Safety: ranking never overrides privacy; degrade without empty leaks
Beginner to advanced path(open guidance)
Beginner answer
Users, posts, follows, feed cache, pagination, likes, comments, and media hydration.
Advanced answer
Candidate generation, ranking, visibility, stable cursors, cache invalidation, ads blending, quotas, chronological fallback.
Deeper walkthrough
News feed deeper walkthrough
A feed is not just a list of posts. It is candidate generation, filtering, ranking, hydration, pagination, and feedback loops.
Requirement refinements
Clarify whether the feed includes only followed accounts, recommendations, ads, groups, privacy filters, and blocked users.
State freshness expectations separately from ranking quality and read latency.
API design details
Use stable cursor pagination because ranked feeds can reorder between requests.
Return tracking metadata for impressions so ranking feedback can learn from what was actually shown.
Data model and storage
Store candidate feeds separately from post content; hydrate content and visibility at read time.
Keep feedback events such as likes, hides, follows, dwell time, and reports in an analytics stream.
Scaling strategy
Use fan-out on write for normal users and pull or merge strategy for celebrity or high-rank accounts.
Cache feed candidates, but recheck post visibility and deletion during hydration.
Reliability, recovery, and operations
If ranking fails, return cached or chronological candidates instead of an empty feed.
Monitor feed p99, candidate freshness lag, ranking latency, visibility-filter misses, and fan-out backlog.
Deepening reference
News Feed: realistic production notes
Beginner mental model: A feed is candidate generation, ranking, hydration, pagination, and freshness management.
Production scope: A production feed blends follow graph content, recommended content, ads, hidden/blocked content, ranking signals, and cache invalidation.
Choose what the first version must guarantee
Start by deciding which news feed capabilities are essential. Describe the main read and write operations before choosing infrastructure. For each operation, identify the stored records it uses and the condition that makes its result correct. A fast response is useful only if it satisfies that condition.
Next, separate work the user must wait for from work that can finish later. Estimate requests per second, storage growth, and the busiest object or customer. Use those estimates to choose one bottleneck to investigate. The calculations below are example workloads with stated assumptions; they are not measured limits of a particular product.
Concrete capacity calculations
Traffic: 100M daily users, 20 feed opens/day means 2B feed reads/day, about 23K/sec average and 115K/sec at 5x peak.
Writes: 10M authors posting 2/day creates 20M posts/day, about 231/sec average. Fan-out, not raw post writes, is the real write multiplier.
Candidate cache: 1,000 candidate IDs per active user at 16 bytes each is 16 KB/user. For 50M cached users this is about 800 GB before overhead.
Ranking budget: if p99 feed latency target is 200 ms, candidate fetch, visibility filtering, ranking, hydration, and network each need explicit sub-budgets.
Invalidation: deleting one popular post from 20M cached feeds is too expensive synchronously. Mark the post unavailable and filter at hydration while async cleanup catches up.
Scaling to millions of users
Split candidate generation, ranking, and hydration into separate stages with fallbacks at each stage.
Partition home-feed caches by reader_id; partition author posts by author_id and time for profile timelines.
Use hybrid push/pull fan-out so popular authors and highly personalized feeds do not explode write amplification.
Keep visibility, blocks, and deleted-state checks close to hydration so cached candidate IDs cannot leak private content.
Use async feature pipelines for engagement signals; stale features should reduce ranking quality, not availability.
Sequence and data-flow diagram
Walk this path after the high-level design so it is clear what is synchronous, what is asynchronous, and where the system can degrade safely.
Read the diagram definition
sequenceDiagram
participant Author
participant Post as Post service
participant Log as Event log
participant Fanout
participant Cache as Feed cache
participant Reader
participant Ranker
Author->>Post: Create post
Post->>Log: Publish post event
Log->>Fanout: Fanout candidates
Fanout->>Cache: Add candidate IDs
Reader->>Cache: Fetch candidates
Reader->>Ranker: Rank and hydrate
Ranker-->>Reader: Feed pageCore flow to walk through
Write post: store post, publish event, fan out to followers or mark for read-time merge.
Read feed: fetch candidates, filter visibility, rank, hydrate, paginate.
Feedback: likes, hides, follows, and dwell time update ranking features asynchronously.
Production readiness
News Feed: ship, operate, and evolve
Now examine the same request flow during failures and deployments. Tie each operational control to the user behavior it protects.
Observability
Track news feed p95/p99 latency, error rate, saturation, and user-visible freshness separately for read, write, and async paths.
Alert on leading indicators such as queue age, hot-key skew, cache miss storms, reconciliation mismatches, and error-budget burn.
Security and abuse
Enforce authentication, authorization, rate limits, input validation, audit trails, and privacy checks at the service boundary.
Treat abuse controls as a first-class path: throttling, quota isolation, moderation hooks, revocation, and safe handling of sensitive data.
Degraded modes
Name what still works if cache, search, ranking, stream processing, object storage, or a regional dependency is slow.
Prefer stale-but-safe reads, partial results, async retry, admission control, and feature disablement over corrupting core state.
Testing and rollout
Load test average, peak, and hot-object traffic; add failure-injection for retries, timeouts, backlog growth, and dependency outages.
Ship with canaries, shadow reads or dual writes when useful, rollback switches, schema compatibility checks, and replay validation.
Runbooks
Document dashboards, paging thresholds, owner actions, rollback steps, data repair commands, and customer-impact language.
Keep backfills and replays idempotent, resumable, rate-limited, and observable so repair work does not create a second incident.
10x evolution
Say which metric forces the next architecture change: shard count, cache footprint, write amplification, queue lag, p99 latency, or regional failover reserve.
Evolve one bottleneck at a time: partition by access pattern, isolate hot tenants, regionalize reads, add replayable async pipelines, then harden multi-region behavior.
Hard parts worth deepening
Do not mix candidate generation and final ranking into one vague service.
Visibility filtering must happen before returning content.
Pagination should use stable cursors, not offset.
Ads and recommendations need separate quotas and blending rules.
Failure modes and recovery
Ranking service down; return chronological or cached feed.
Fan-out backlog; feed freshness degrades but reads continue.
Deleted/private post remains in cache; hydrate path must recheck visibility.
Celebrity post overload; use hybrid fan-out.
Signals to monitor
Feed p99 measures response speed, while freshness lag measures the age of newly available content. Neither replaces the other: a cached response can be fast and stale.
Candidate count explains ranking workload, and ranking latency shows whether that workload fits the request budget. Visibility-filter misses must distinguish ordinary excluded candidates from restricted content that escaped into the delivered response.
| Choice | Best when | Cost |
|---|---|---|
| Push model | Reads dominate and follower counts are moderate. | High write amplification. |
| Pull model | Authors have massive followers or feed is highly personalized. | Read latency and CPU. |
| Ranked feed | Engagement and personalization matter. | Explainability and freshness complexity. |
Try this scenario
Describe how you remove a private post from millions of cached feeds without scanning every feed synchronously.
Primary sources
- Bronson et al.: TAO (USENIX ATC 2013): social graph read path.
- Scaling Memcache at Facebook: feed fanout caching.
- Kafka Docs: Topics: async fanout pipelines.
Practice and further reading
Use these exercises to connect the lesson to a design decision. State your assumptions, trace what happens to one request, and explain the rule that must remain true even during a failure. That rule is the design's correctness invariant.
Focus for this lesson: Design candidate generation, feature hydration, ranking, experimentation, stable pagination, impression logging, feedback, and deletion/privacy filtering.
Explain the decision
How does a generic ranked news feed differ from a follower timeline?
Read the reasoning
It blends many candidate sources and model features, then needs experiment assignment, impression/click labels, diversity, and ranking-version observability.
Apply it to a production scenario
A new model lifts clicks but increases hides and latency. Should it ship?
Read one approach
Evaluate guardrail metrics, cohort/fairness effects, long-term outcomes, capacity, and rollback; CTR alone is not the product objective.
Work through the numbers
Ranking 2,000 candidates for 100,000 requests/s at 50 features each implies how many feature reads/s naively?
Read the worked calculation
Ten billion feature values/s; batch, cache, precompute, and reduce candidates before expensive ranking.
Reason through a failure
What must impression logging preserve?
Read the recovery reasoning
The exact ranking/model/experiment and visible items are attributable without double-counting, so training and product metrics remain trustworthy.
Sources and further study
Continue with Design Distributed Cache.