System design interview guide
Facebook Feed System Design
Your friend posted ten minutes ago but your feed still looks like yesterday— fan-out lag or a slow ranker is the product failure, not a missing database box. Hybrid fan-out, a celebrity policy, and honest degradation when ranking times out are what interviewers grade on a Facebook-style home feed.

Problem statement
You're designing a Facebook-style home feed: posts from people and pages someone follows, ranked or chronological, paginated, and fast to scroll.
Functionally you need create post, follow graph, home feed pages, optional reactions and comments, rank or recency modes, and block or mute. Non-functionally you need roughly sub-300 ms feed p95 for the common path, high availability, and durable posts—while ranking may lag by seconds. Scale sits at hundreds of millions of daily actives with reads far exceeding writes, and a few accounts with follower counts so large that naive fan-out becomes a cost and reliability incident.
What interviewers reward: hybrid fan-out with a celebrity policy; mailboxes of IDs separate from post bodies; bounded candidates and ranker timeouts; cursor pagination with honest dup/skip; degrade ranking—not a blank feed—when dependencies fail.
Introduction
You open the app after lunch. Your friend posted a photo ten minutes ago, but your feed still looks like yesterday. You pull to refresh. Nothing changes. The post “succeeded” for them—your timeline is just behind.
That feeling is the product problem. The interview is the machinery behind it: reads crush writes, a few accounts have massive follower counts, and any design that does unbounded work per swipe or fans out every post to every follower breaks in cost and tail latency before it breaks on the whiteboard.
Interviewers are not grading box count. They want three ideas you can explain in plain language:
- Push vs pull vs hybrid — where you pay cost on publish versus on scroll.
- Split storage — feed rows are IDs and order; post bodies and media live elsewhere.
- Honest fuzz — ranking moves, graphs change, pagination will duplicate or skip sometimes; say that out loud.
Weak answers draw a message queue with no celebrity policy. Strong answers walk one write and one read and name what degrades when the fan-out queue or ranker lags.
If you remember one thing: The home feed is a bounded read path over precomputed candidates—not one giant join on every scroll.
How to approach
Start the way a user experiences the product, not by listing every service name. Spend the first few minutes turning “design Facebook feed” into a contract you can design against. Talk through clarifying questions out loud, then walk one publish and one home page before you name storage brands.
Clarifying questions (say these in the room)
Start with what “feed” means and whether ranking is required, because those answers change fan-out policy and the entire read path.
You: “Is this only the home feed from people and pages I follow, or do we also need groups, pages you do not follow, and ads in the same round?”
Interviewer: “Home feed from follows; ads and groups can stay out of scope.”
That answer keeps you on candidate generation and fan-out instead of building an ads auction on day one.
You: “Is ranking in scope—“Top stories”—or is chronological “Most recent” enough for this interview?”
Interviewer: “Assume a ranked home feed with a fallback to recency.”
Now you know you need a ranker interface with a time budget, not only a mailbox dump sorted by time.
You: “What does fresh mean in seconds—is it okay if friends see a post a few seconds after publish, as long as blocks and safety are correct?”
Interviewer: “Eventual visibility for friends is fine; blocks must not wait.”
That permission lets you async fan-out while still filtering blocks on the hot read path.
You: “Should I treat accounts with tens of millions of followers as a special case, or assume every author is a normal user?”
Interviewer: “Call out the celebrity case explicitly.”
You now owe the room a hybrid policy—not “we fan out to everyone.”
You: “I want to leave full ads ranking, Reels recommendation, and the complete ML training stack out of scope so we can focus on publish, fan-out, home read, and ranker timeouts. Does that match what you want?”
Interviewer: “Yes—focus on home feed at scale.”
Saying out of scope early stops you from spending the round on adjacent products.
Minute pacing (about 45–60 minutes)
| Minutes | Focus |
|---|---|
| 0–5 | Clarify home vs ranking, freshness, celebrities, out of scope |
| 5–12 | Capacity: read:write skew + one celebrity fan-out estimate |
| 12–25 | Write path + hybrid policy; data model (mailbox vs post) |
| 25–40 | Read path dig: candidates, hydrate, filter, rank, cursor |
| 40–50 | Failure / one production scene |
| 50–60 | Questions / deepen one tradeoff |
In the room (a fuller opening you can actually say): “I will design the home feed from follows. Posts become durable first; fan-out to follower mailboxes runs asynchronously with idempotent writes. For normal authors I push; for mega-followed authors I merge on read so I do not write tens of millions of rows per post. On read I load a bounded candidate set of post IDs, batch-fetch bodies, filter blocks, score under a hard timeout with a recency fallback, and return an opaque cursor. Ranking can be seconds stale; empty feed on ranker failure is not acceptable.”
Out of scope (and why you park these)
Write a short out-of-scope list on the board so the interviewer sees you can bound the problem.
Full advertising auction and billing. Ads change ranking and money flows, but they steal the interview from hybrid fan-out and read-path budgets. You can note “ads inject candidates later” without designing the auction.
Training the ranking model end to end. You need the serving interface: candidates in, scores out, timeout behavior. Building feature stores and training pipelines is a different interview.
Groups, Stories, Reels, and Marketplace as full products. Each has its own fan-out and ranking story. Mention them only if the interviewer expands scope.
Strongly consistent worldwide visibility the millisecond someone posts. Home feed almost always accepts short lag. Promise instant global mailbox sync and you invent a harder problem than the room asked for.
Capacity estimation
Before you draw architecture boxes, use rough numbers so you do not promise impossible per-scroll work.
| Dimension | Rough scale | What this means for your design |
|---|---|---|
| DAU | Hundreds of millions | Home reads dominate; cache and shard aggressively |
| Posts per day | Hundreds of millions globally | Write QPS is modest next to read QPS |
| Follow edges | Highly skewed | Median follows are manageable; celebrities dominate cost |
| Fan-out for 50M followers | 50M mailbox writes per post if naive | Must be policy-exempt or partial—async queue alone does not save you |
| Feed page size | Tens of posts | Bound candidates before rank; never score the whole graph |
Worked skew sketch: If one celebrity posts once and you fan out to fifty million followers, you create on the order of fifty million mailbox inserts for a single click—before media processing or notifications. That is why “always fan out” fails, even with a fast queue.
If you remember one thing: Numbers exist to show skew—reads dominate, celebrities break naive fan-out.
High-level architecture
What breaks if you merge everything
One service that stores full post JSON in every follower’s feed, ranks with no timeout, and blocks create-post until every mailbox is written will choke on celebrity traffic and hang the edge when ML slows down. Logging every ranking feature online into the critical path makes p95 worse without teaching anyone in the room.
What works: IDs on the timeline, bodies elsewhere
Who owns what:
- API / edge — Auth, rate limits, timeouts to downstreams.
- Feed service — Orchestrates the read path: candidates, graph checks, hydrate, rank, cursor. This is where you cap work.
- Mailbox / timeline store — Ordered post IDs (or score+id) per viewer, sharded by
user_id. - Post service + object storage + CDN — Source of truth for post metadata and media bytes.
- Graph service — Follow, unfollow, block, mute—cached carefully on the feed path.
- Fan-out workers — Consume a queue; append to mailboxes where push policy allows; idempotent
(viewer_id, post_id). - Ranker — Scores a bounded candidate set under a hard time budget.
Celebrity / hybrid on the whiteboard: For authors you do not fully fan out, the feed service merges recent posts by author into the candidate pool. Draw that edge—or you only drew push fan-out and invite the follow-up you deserve.
[ Client ]
→ [ LB / API gateway ] → [ Feed svc ] → [ Mailbox store / celebrity merge ]
| ↓
| [ Ranker + timeout ]
| ↓
+-- [ Graph ] response + cursor
+-- [ Post svc ] ← media via CDN
|
[ Post create ] → durable post → [ Fan-out queue ] → workers → mailboxes
In the interview: Narrate the read path first (latency budget, bounded candidates, ranker timeout). Then one write (durable post → async fan-out → idempotent mailbox writes). Storage brand names come after the story makes sense.
If you remember one thing: Read path is IDs → batch hydrate → rank with timeout; write path acks before every mailbox row exists.
Core design approaches
Fan-out on write (push)
After a post is stored, push its ID into each follower’s mailbox. Reads feel cheap because the heavy work already happened.
The catch is the O(followers) wall. The moment you say “we fan out to everyone,” you owe the room a celebrity exception—or you have designed a machine that spends your cloud budget as a distributed write storm.
Pull on read
At request time, pull recent posts from followed accounts and merge. That dodges the celebrity write blast, but you can spend a lot of CPU merging when someone follows thousands of accounts—so real systems cap, cache, or hybridize.
Hybrid (what production usually sounds like)
| Policy | When it fits | Cost you accept |
|---|---|---|
| Push to follower mailboxes | Long-tail authors (modest follower counts) | Storage and fan-out CPU on publish |
| Merge / pull recent by author | Celebrities and mega-pages | Extra work on the home read path |
| Partial fan-out to active users | Middle tier or “online now” optimization | Stale mailboxes for inactive viewers |
Push for the long tail. For mega-followed authors, do not materialize every edge. The exact threshold matters less than saying there is a policy and naming the cost driver (queue depth, storage, blast radius).
If you remember one thing: Hybrid is the real answer—pure push or pure pull alone fails at this scale.
Data model
Keep three ideas separate: what each viewer scrolls, what a post is, and who can see whom.
Mailbox / timeline (per viewer)
| Field / concept | Why it exists |
|---|---|
viewer_id | Shard key for that person’s home timeline |
post_id | Pointer into the post store—not the full body |
score or created_at | Ordering hint for recency or last known score |
author_id | Helps celebrity merge and filter |
Idempotency on (viewer_id, post_id) | Retries must not duplicate rows |
Posts and media
| Concept | Store | Note |
|---|---|---|
| Post metadata | Post service / DB | Author, text, privacy, timestamps, media keys |
| Media bytes | Object storage + CDN | Upload before or beside create; feed path only carries URLs or ids |
| Author profile cache | Cache / profile svc | Safe to be slightly stale for display names |
Graph
| Edge | Hot-path rule |
|---|---|
| Follow | Drives fan-out membership and pull-merge sets |
| Block / mute | Must filter on read even if mailboxes lag |
| Unfollow | May purge asynchronously; filter until purge completes |
Interview land: Draw “mailbox = ordered IDs” and “post store = bodies” as two boxes. One database that stores full JSON in every follower row is the anti-pattern.
Detailed design
Tell the story like an outage retro for one post and one scroll—that is how interviewers decide whether you understand the product clocks.
Write path
When someone publishes, large media should already be landing in object storage (or uploading in parallel), while the post service writes the durable metadata: author, text, privacy, media ids, timestamps. The create API returns success once that metadata is safe. It does not wait until every follower’s mailbox row exists—that wait is how celebrity posts time out.
Fan-out then runs asynchronously: workers append the post id into follower mailboxes where hybrid policy allows push, using an idempotent key so retries do not duplicate entries. Search indexing, notifications, and link previews can trail afterward. If you put those on the critical create path, you miss latency targets and still sometimes generate the wrong preview image.
Read path
Scrolling home is a different budget. Load a bounded chunk of candidate post ids for this viewer—usually from a precomputed mailbox, plus any celebrity merge-on-read. Batch-fetch the post bodies and author cards for those ids only. Apply block and hard safety filters here even if an old id still sits in a mailbox. Then score under a hard time budget; if the ranker is late, return a recency-ordered or last-good slice instead of hanging the app. Finish with an opaque cursor so the next page can continue when ranks move between requests.
If your whiteboard answer stops at “we call the ML service,” the follow-up will be: what happens when that service is slow? Strong answers already have the timeout and fallback in the read story.
In the room (spoken): “Create returns after durable metadata; fan-out catches up asynchronously with hybrid policy for big authors. Home scroll loads capped ids, hydrates in batch, filters blocks, ranks with a timeout, and returns a cursor—post 201 and ‘friend sees it’ are two different clocks.”
Architectural dig: one home-feed page (and one celebrity publish)
High-level boxes showed ownership. This dig is how scroll stays fast when a celebrity posts and when the ranker misbehaves.
1) Publish: durable post, then policy-aware fan-out
Responsibility: Post service owns durability and identity (post_id). Fan-out workers own mailbox appends where push is allowed. Feed service must not wait on millions of inserts before returning 201.
- Validate author and content policy (light checks on create).
- Persist post metadata; associate already-uploaded
media_idsif any. - Enqueue fan-out job
{ post_id, author_id, follower_tier_policy }. - Workers expand followers (or skip full expand for celebrity tier) and write idempotent mailbox rows.
2) Celebrity blast radius (bad vs great)
Bad design: always push to every follower
A page with fifty million followers hits Post. Workers attempt fifty million mailbox writes. The fan-out queue ages; friends’ feeds look stale for minutes while create-post dashboards stay green.
Post 201 ──► enqueue fan-out ──► 50M mailbox writes
│
└── queue age ↑ while API success looks fine
Great design: hybrid policy by follower tier
Classify the author. Long-tail: push. Mega-followed: store in an author-indexed recent list and merge on read into each viewer’s candidate set (optionally push only to recently active viewers).

Figure: Follower count picks whether you pay on publish or on scroll. Pure push to everyone is a cost and lag incident waiting to happen.
Scale inside the box: Monitor queue age, writes per shard, and time-to-first-visibility for sampled posts—not only create 201 rate.
Failure inside the box: If workers die mid-fan-out, idempotent retries finish the long tail; celebrity merge still lets actives see content from the author store.
3) Read: bounded candidates under a rank budget
- Authn viewer; load block/mute set (cache with strict freshness for blocks).
- Read mailbox head (and merge celebrity tails) → cap N candidates (for example a few hundred, not “everyone you follow forever”).
- Batch-get posts + authors; drop tombstones and blocked authors.
- Call ranker with deadline T ms; on timeout use recency or last known order.
- Return page of size K + opaque
next_cursor.
Interview land: “I never let ranking see an unbounded set, and I never let ranking own the edge’s thread pool without a timeout.”
4) Pagination when scores move
Between page 1 and page 2, ranks and new posts arrive. Offset/limit skips and duplicates badly. Prefer an opaque cursor that encodes enough to continue (session snapshot or (score, post_id)). Admit best-effort stability: clients should skip duplicates; rare skips are okay.
5) Numbered happy path (put it together)
- Create post → durable
post_id→ 201. - Fan-out (or celebrity skip) → mailbox IDs where policy allows.
- Home GET → candidates → hydrate → filter → rank or fallback → cursor.
- Next page uses cursor; graph filters still applied.
If you remember one thing: Success on create and a fresh feeling feed are two different SLOs.
Key challenges
| Challenge | What users see if it goes wrong | What to say in the interview |
|---|---|---|
| Celebrity fan-out | Friends’ feeds stuck while posting still “works” | Hybrid policy; queue age alerts; merge on read |
| Moving ranks | Duplicate posts or gaps while scrolling | Opaque cursors; admit best-effort dup/skip |
| Graph churn | Blocked user still appears; unfollow hangs | Filter blocks at read; async purge / TTL |
| Ranker lag | Spinners or empty feed | Timeout + recency fallback; circuit breaker |
| Hot post cache stampede | One viral ID melts post store | Singleflight, TTL jitter, watch origin QPS per key |
If you remember one thing: Skew picks fan-out policy; moving rank picks cursor honesty.
Scaling the system
Shard mailboxes by viewer_id. Shard posts by id or author-time. Avoid multi-table joins on the hot home path—hydrate by id batch.
Cache hot post bodies, profiles, and following-set snapshots. Use TTL jitter and request coalescing so one viral post_id does not align every miss.
Multi-region: Prefer local reads with eventual fan-out replay. Do not claim one globally strongly consistent mailbox view unless the interviewer forces that harder problem.
Cap pull-merge fan-in when someone follows thousands of accounts—otherwise hybrid still burns CPU on read.
If you remember one thing: Scale reads with sharded mailboxes + CDN; scale writes with async fan-out + celebrity caps—not bigger SQL joins.
Failure handling
| Scenario | What the user sees | What to build |
|---|---|---|
| Ranker slow or down | Spinners or empty home | Hard timeout; recency fallback; feature-flag heavy models |
| Fan-out backlog | Post succeeded; friends see stale home | Alert on queue age; lean on merge-on-read; priority lanes |
| Cache stampede on hot post | p99 spike on one ID | Singleflight; stale-while-revalidate; jittered TTL |
| DB / post store degraded | Errors or blank cards | Circuit break; serve stale-but-safe slices where product allows |
If you remember one thing: Degrade ranking (recency, stale slice)—do not block the edge forever behind a slow ranker.
API design
Illustrative REST-style surface (GraphQL is fine if you name batching and field cost—feeds are where naive graphs hurt).
POST /v1/posts
GET /v1/me/home
GET /v1/posts/{post_id}
POST /v1/users/{user_id}/follow
DELETE /v1/users/{user_id}/follow
Home feed — GET /v1/me/home
| Query param | Role |
|---|---|
cursor | Opaque continuation (preferred) |
limit | Page size (cap server-side, e.g. ≤ 50) |
ranking | top or recent |
session_id | Optional session snapshot for experiments |
Response sketch: { "items": [ Post ], "next_cursor": "...", "has_more": true }.
Errors: 401 unauthenticated; 429 with Retry-After when throttled. Avoid leaking whether a blocked user exists—use generic 404/403 per product policy.
Create post — POST /v1/posts
Use an Idempotency-Key so mobile retries do not create duplicate stories. Body carries text and media_ids[] already uploaded via separate upload URLs—do not put video bytes in JSON. Success is 201 with post_id and a processing state for media (pending / ready).
Follow graph
POST / DELETE follow return quickly. Graph updates are eventually visible in feed—say so if asked. Blocks remain a read-path safety filter regardless.
Cross-cutting behavior to name in the interview
- Rate-limit create and follow separately from home read.
- Document cursor opacity and moving-rank semantics.
- Keep reactions/comments off the feed p95 critical path unless scoped in.
In the interview: One minute on idempotent create, cursor semantics for home, and why ranking is not allowed to hang the gateway is enough to sound shipped—not memorized.
Observability (what you measure)
| Signal | Why it matters |
|---|---|
| Post create success vs fan-out queue age | Explains “posted but friends don’t see it” |
| Time-to-first-visibility (sampled) | Product freshness SLO |
| Ranker p99 + timeout / fallback rate | Separates rank health from feed availability |
| Candidates scored per request | Catches unbounded merge |
Origin QPS per hot post_id | Stampede detection |
| Empty feed / 5xx rate | User-visible outages |
Green create rates alone will lie while timelines feel stale.
Security and abuse
Authenticate every home and create call. Authorize visibility (friends-only, public, blocked) on read, not only at fan-out time. Rate-limit post create, follow, and react to slow spam and follow-bots. Treat ranking logs carefully—do not dump private post bodies into unrestricted analytics without access control. Abuse and integrity pipelines (fake engagement, coordinated amplification) belong beside the feed, not as an afterthought that rewrites every mailbox synchronously.
Cost awareness
Every pushed mailbox row costs storage and write IOPS forever (or until TTL). Celebrity push-to-all is a cloud bill incident, not a clever scale story. Scoring huge candidate sets burns CPU on every scroll. CDN and object storage dominate media cost; keep blobs off the mailbox path. Caching reduces post-store load but multiplies complexity—buy cache where keys are hot and stamps are measurable. Choose explicitly whether you spend money on precompute storage or read-time merge CPU.
When users are stuck but the dashboards look fine
Textbooks teach boxes and arrows. On-call teaches this: post create can look healthy while the home feed feels stuck in yesterday.
Three nightmares that look fine in the middle:
| What the dashboard shows | What is actually happening |
|---|---|
| Post create 201 rate is green. | Fan-out queue age is climbing; friends refresh and see old stories. |
| Ranker error rate is low. | Ranker p99 ate the gateway thread pool; feeds hang without many 5xx. |
| Cluster CPU looks calm. | One viral post_id is stampeding the origin after a synchronized TTL expiry. |
Scene 1: Fan-out backlog while posts “succeed”
The moment: A live event or celebrity posts. Create still works. Friends refresh and still see yesterday’s top of feed.
The trap: Fan-out is async. Workers append at finite speed. Dashboards that only chart create success hide time-to-visible.
What to build: Alert on queue age and per-shard backlog. Cap fan-out per tick; lean on read-side merge while the queue drains. Priority lanes for recent posts vs backlog drain.
Scene 2: Ranker deploy hangs the feed
The moment: After a ranking release, homes spin; unrelated routes feel slow.
The trap: Ranker sits on the hot path without isolation. Missing timeout fills the edge thread pool.
What to build: Hard rank timeout; circuit breaker; recency fallback; kill switch for heavy models. Separate SLOs: feed loads vs perfect rank.
Scene 3: “I see it, you don’t”
The moment: Coworkers disagree whether a viral post appeared.
The trap: Global fan-out is not one transaction. Regional shards and at-least-once workers mean eventual visibility.
What to build: Idempotent mailbox writes; dashboards on cross-region lag. Do not promise instant worldwide materialization.
Scene 4: Cache stampede on a hot post ID
The moment: One viral post; feed still loads but p99 spikes; post service catches fire while “average cache hit ratio” looks fine.
The trap: Every scroll multi-gets the same post_id. Aligned TTL expiry creates a miss herd.
What to build: Singleflight per key; TTL jitter; stale-while-revalidate; watch origin QPS on one key, not only cluster CPU.
In the interview: Pick one scene. Tell what users felt, which metric lied, and what you would ship next.
Bottlenecks and tradeoffs
Precompute vs read-time merge
The tension — Materializing every follower’s mailbox makes scroll fast; celebrities make write amplification impossible.
What breaks — Fan-out queue depth explodes; one post fans out to tens of millions of rows.
What teams do — Hybrid: push for normal accounts, merge on read for the head; alert on queue age.
Say in the interview — Name who you fan out to and who you merge at read—not “we fan out.”
Fresh ranking vs stable pagination
The tension — Users want relevant order; cursors want stable continuation.
What breaks — Duplicates or skips when scores shift between page loads.
What teams do — Opaque cursors, session snapshots, client-side dup skip; admit best-effort.
Say in the interview — Offset/limit at scale is a trap; cursor + honesty beats fake consistency.
Cost vs freshness
The tension — More precomputed mailboxes smooth reads; they cost storage and fan-out CPU.
What breaks — Thin mailboxes push merge work into p99 read when someone follows thousands of accounts.
What teams do — Cap candidates before rank; TTL trim on mailboxes; tier storage for cold tails.
Say in the interview — Pick what you buy with money: storage or read CPU.
If you remember one thing: Every feed tradeoff is where you pay—publish, scroll, or ops when queues lag.
Interview tips
You have the full design in mind now. These five back-and-forths are how interviewers test whether you can defend it under pressure. Each one starts with a tempting shortcut, an interview push, and a clear answer.
Fan-out on write only — celebrities melt the queue
You might say: “When someone posts, we fan out to every follower’s mailbox.”
Interview Push: “A page with 50 million followers hits Post—what happens to your queue and storage?”
Land here: That is on the order of fifty million mailbox writes for one click if you are naive. Use a hybrid policy: push for the long tail where fan-out is cheap; for mega-followed authors, merge on read, partial fan-out to active users, or store by author and intersect at scroll time. Name queue depth and blast radius, not only “we use Kafka.” If create returns 201 while queue age climbs, friends’ feeds still look stale—and that is an ops story you should volunteer.
Where post bodies live — pointers on the timeline
You might say: “The feed service stores everything in one database.”
Interview Push: “What travels on every scroll—full post JSON or pointers?”
Land here: The mailbox / timeline store holds ordered post IDs (or score+id) per viewer, sharded by user_id. The post service plus object storage and CDN own bodies and media. The feed path multi-gets by id and caps work. Shipping full bodies in every follower row multiplies storage and makes edits and deletes painful.
Ranking as one box — timeouts beat perfect scores
You might say: “We call the ML service and sort.”
Interview Push: “Ranker p99 doubles—does the whole app hang?”
Land here: Separate candidate generation (bounded list of IDs) from scoring. Put a hard timeout on rank; fall back to recency or the last good slice. Add a circuit breaker so the edge does not block on one dependency. Perfect ranking that empties the feed is a product failure, not a win.
Pagination with moving order — cursors over offsets
You might say: “We use offset and limit—page 2 is easy.”
Interview Push: “Scores change between requests—do users see duplicates or gaps?”
Land here: Use an opaque cursor or (score, post_id) continuation. Admit best-effort stability—rare duplicates or skips—rather than fake strong consistency. Offset pagination at feed scale is a trap because the list underneath the offset keeps moving.
Blocks and unfollows — safety now, purge later
You might say: “We delete all feed rows when someone unfollows.”
Interview Push: “At a billion edges, can you recompute every mailbox synchronously?”
Land here: Graph updates are eventual for unfollow. Filter blocks at read for safety even if a stale ID still sits in a mailbox. Use TTL, lazy filter, or compensating deletes for soft graph churn. Brief unfollow staleness is usually okay; block paths are not.
Red flags to avoid without correcting yourself: “Fan out to everyone,” “offset pagination,” “rank with no timeout,” “one DB holds full posts in every feed,” “recompute all mailboxes on unfollow.”
After each interview push, close with one real part of the design you would build—hybrid threshold, idempotent (viewer_id, post_id), ranker timeout, or opaque cursor—not “we’ll scale it later.”
What should stick
After reading this guide, you should be able to explain:
- Read:write skew — Almost everyone scrolls; few post; celebrities break naive fan-out.
- Hybrid fan-out — Push where cheap; merge or pull for the head; policy by follower count.
- IDs vs bodies — Mailboxes hold order; posts and media live elsewhere; batch hydrate.
- Ranker is best-effort — Bounded candidates, timeout, recency fallback—never block the edge.
- Cursors over offsets — Moving rank means honest dup/skip, not fake strong consistency.
Tell it in the room: “Home feed: durable post, async idempotent fan-out to shards where policy allows, read path loads capped candidate IDs, multi-gets bodies, filters blocks, ranks with a timeout, returns a cursor. Celebrity: no O(followers) write—merge on read. When fan-out lags, users still scroll stale mailboxes; when ranker lags, fall back to recency.”
Key Takeaways
- Clarify first — Home vs ranking, freshness seconds, celebrity policy, out of scope.
- Hybrid fan-out — Push the long tail; merge mega-authors on read.
- Split storage — Mailboxes store IDs; posts and media live elsewhere.
- Bound the read path — Cap candidates; hydrate in batch; filter blocks; rank with a deadline.
- Degrade ranking, not the feed — Recency fallback beats empty spinners.
- Honest cursors — Moving scores mean occasional dup/skip; offsets lie.
- Operate queue age and hot keys — Create 201 can look fine while timelines feel stale.
Related Topics
- WhatsApp System Design - Messaging contrast: per-thread order vs feed fan-out and ranking
- Notification Service System Design - Async fan-out after the durable write
- Rate Limiter System Design - Protecting create and follow from abuse
- Distributed Cache System Design - Hot post keys, stampede, and TTL jitter
- Facebook Post Search System Design - Search indexing beside the hot home path
Quick revision notes
Use this as a last look before a mock interview, not as a substitute for the full guide.
Clarify first. Agree home-only scope, whether ranking is required, how many seconds of freshness friends can tolerate, that celebrities need a special policy, and what you leave out (ads ML train, Reels). Skipping this often means you draw Kafka with no cost story.
Pay on publish or on scroll—pick by follower tier. Push mailbox IDs for normal authors. For mega-followed authors, merge recent posts on read so one publish does not become tens of millions of writes.
Keep the timeline thin. Mailboxes store ordered IDs. Post bodies and media hydrate in batch. Ranking scores a bounded set under a timeout and falls back to recency when the model is slow.
Paginate honestly. Opaque cursors beat offsets when ranks move. Blocks filter on read even if unfollow cleanup is eventual.
Operate the lag. Alert on fan-out queue age, ranker timeouts, and hot post_id origin QPS—because green create rates and an angry “my feed is stuck” can coexist.
Practice this path: Facebook Feed System Design.
What interviewers expect
- Hybrid fan-out: push for the long tail; merge or pull for mega-followed authors.
- Split storage: mailboxes hold ordered post IDs; post bodies and media live elsewhere.
- Bounded read path: candidates → batch hydrate → safety filters → rank with timeout → cursor.
- Ack before full fan-out: post create succeeds when metadata is durable; followers catch up async.
- Degrade ranking, not the feed: recency fallback when the ranker is slow.
- Honest pagination: opaque cursors; occasional duplicates or skips when ranks move.
Interview workflow (template)
- Clarify requirements. Confirm functional scope, users, consistency needs, and which non-functional goals matter most (latency, availability, cost).
- Rough capacity. Estimate QPS, storage, and bandwidth so your data model and partitioning story are grounded.
- APIs and core flows. Define a minimal API and walk 1–2 critical read/write paths end to end.
- Data model and storage. Choose stores for each access pattern; call out hot keys, indexes, and retention.
- Scale and failure. Add caching, sharding, replication, queues, or fan-out as needed; say what breaks in failure modes.
- Tradeoffs. Name alternatives you rejected and why (e.g. strong vs eventual consistency, sync vs async).
Frequently asked follow-ups
- Fan-out on write vs pull on read vs hybrid?
- How do you handle 50 million followers?
- What happens when the ranker is slow?
- How do you paginate when scores change?
- What do you alert on when posts succeed but feeds feel stale?
Deep-dive questions and strong answer outlines
Walk through a normal user publishing one post.
Persist post metadata (and media via a separate upload path). Return success once the post is durable—do not wait for every follower mailbox. Enqueue async fan-out with idempotent writes keyed by (viewer_id, post_id). Long-tail followers get mailbox appends; mega-followed authors follow the celebrity policy (skip full fan-out, merge on read). Offload search index, notifications, and link previews after the post row exists.
How do celebrity accounts change the write path?
Do not materialize O(followers) mailbox rows for tens of millions of edges. Mark the author for hybrid policy: store by author, fan out only to active viewers, or merge recent posts on read into each home candidate set. Say the cost drivers—queue depth, storage, blast radius—not only “we use Kafka.”
Walk through reading one page of the home feed.
Load a bounded set of candidate post IDs from the viewer mailbox plus any celebrity merge. Batch-get post bodies and authors. Filter blocks and hard safety rules. Score under a hard timeout (or fall back to recency). Return items plus an opaque next_cursor. Cap candidates so p95 stays in budget.
What if the ranker p99 doubles after a deploy?
Hard timeout on ranking; circuit breaker; return a recency-ordered slice or last good candidate order. Separate SLOs for “feed loads” vs “perfect rank.” Do not let the API gateway thread pool block forever on one dependency.
Someone unfollows or blocks—how does the feed update?
Blocks must be enforced at read for safety (cached block list is fine if fresh enough). Unfollow can be eventual: filter at read, TTL stale mailbox entries, or run compensating deletes asynchronously. Do not recompute every mailbox synchronously at a billion edges.
AI feedback on your design
After a practice session, InterviewCrafted summarizes strengths, gaps, and interviewer-style expectations—similar to a written debrief. See a static example report, then practice this problem to get feedback on your own answer.
FAQs
Q: How deep into ML ranking do I need to go in a system design interview?
A: Usually you describe the interface—inputs (candidate IDs, features), a time budget, and what happens on timeout—not training pipelines. Name freshness SLAs and a recency fallback. If they push on models, keep one sentence on features and return to fan-out and pagination.
Q: Is fan-out on write enough by itself?
A: Pure push works for modest follower counts and fails for celebrities. Pure pull works for mega-authors and can burn CPU when someone follows thousands of accounts. Strong answers name a hybrid policy with an explicit threshold or author tier.
Q: Do feeds need strong consistency across every follower instantly?
A: Usually no. Seconds of lag after publish are acceptable for home feed. Blocks and hard safety are stricter—filter at read even if mailboxes lag. Say the consistency bar out loud so you are not promising a global atomic fan-out.
Q: How is a news feed different from a chat product like WhatsApp?
A: Feeds optimize read fan-out, ranking, and scroll latency. Chat optimizes per-thread order, delivery receipts, and often strong privacy. Feeds tolerate brief staleness; chat users notice hundreds of milliseconds. See WhatsApp System Design for the messaging contrast.
Q: Why not offset/limit pagination for home feed?
A: Rankings move between requests. Offsets skip or duplicate as items shift. Opaque cursors (or score+id continuations) plus client-side duplicate skip are the honest contract at scale.
Q: What should I alert on in production?
A: Fan-out queue age and per-shard backlog, ranker p99 and timeout rate, time from post create to first mailbox visibility for sampled authors, cache origin QPS on hot post IDs, and feed empty-error rate—not only post create 201s.
Practice interactively
Open the practice session to use the canvas and stages, then review AI feedback.