System-design interview · Core interviews
Design a personalized news feed
Separate publication, candidate generation, ranking and delivery so a personalized feed remains explainable, recoverable and safe when relationships change.
You will learn to
- Build a complete feed before choosing precomputation and personalized ranking.
- Use audience activity and follower skew to justify hybrid candidate generation.
- Keep stable page sessions separate from current eligibility and recoverable candidate storage.
Practice in this chapter
8 interview questions with model answers and follow-ups.
Go to interview practiceUseful foundations: Database indexes: B-trees, composite keys and query access · Caching: cache hits, misses, write policies and invalidation · Message queues, event logs, delivery guarantees, and backpressure · Real-time communication: polling, long polling, SSE, and WebSocket
Workload and timing examples are interview assumptions.
Dotted concept links open the relevant explanation in a new tab.
01Separate finding stories from deciding their order
Design a personalized feed of posts from followed people, pages and groups. Leo opens the application and receives twenty eligible stories, including Maya’s trail report p882. Publication stores Maya’s post; candidate generation finds possible stories for Leo; ranking orders those candidates; delivery returns the selected content. These are separate responsibilities even if one application initially performs them all.
Include text and references to already uploaded media, follow/unfollow, block rules, group membership, reply filtering, refresh and older pages. Ads, recommendation-model training and video processing are outside scope. A few seconds of propagation delay is acceptable for newly published stories, but current eligibility controls what each response may disclose.
A follow expresses distribution interest. It does not automatically grant access to friends-only or private-group content. Friends-only stories require the product’s approved friendship relation; private-group stories require current membership. Keep those relationship types explicit instead of using one generic edge as every kind of permission.
Choose a bounded ranked browsing session: its ordering stays fixed while the user pages, except that newly ineligible stories can disappear. Refresh starts a new session and includes newer posts. Already delivered content cannot be recalled after a later block or deletion.
Clarify which relationships make a story eligible, whether the feed is ranked, how fresh it should be and whether page two must preserve an earlier order. These choices determine both the candidate pipeline and its browsing-session contract.
02Functional requirements
Agree on these supported actions before selecting components.
Publish and manage stories. Authenticated authors publish/delete posts referencing verified media. Retried creation returns the same durable source post.
Manage eligible sources. Support follows/unfollows, blocks, approved friendships and private-group membership, with each relation retaining its distinct access meaning.
Read a ranked feed. Return up to twenty eligible stories from followed people, pages and groups; apply reply filtering and a declared ranking policy.
Refresh and continue. Refresh creates a new browsing session; older pages continue a bounded stored order while rechecking current eligibility.
03Non-functional requirements
Use these as illustrative interview assumptions to agree with the interviewer. Numerical targets require measurement; they are not claims about an existing product or a proven implementation. p95 (the 95th percentile) means 95% of measured operations finish within the stated time.
Workload. Plan for approximately 86,805 feed requests/s at the fivefold peak, 500 followed entities per reader and skewed authors with millions of active recipients. Candidate reads/writes and media bytes need separate budgets.
Response latency. Target regional p95 feed-metadata latency of 300 ms at admitted peak load in normal operation, including candidate merge, ranking and eligibility checks. Media transfer has a separate delivery measurement.
Freshness. Target p95 propagation from source commit to the candidate lists or author histories used by eligible active readers’ refreshes within five seconds during normal fanout processing. Bounded retrieval and ranking can omit an available story; a retained session intentionally keeps its prior order.
Source durability and recovery. Accepted posts, relationships and publication events must survive a process restart or one database-node failure within the region. Candidate lists and session caches may be lost and rebuilt or restarted without losing source posts.
Access and paging consistency. Check current eligibility for the exact returned content version, even on cached candidates and older pages. Sessions expire after five minutes; a new session may rank differently. Already released content cannot be recalled.
Bounded ranking and degradation. Rank a bounded retrieved pool and disclose that it is not a global optimum. If ranking fails, use eligible chronological results; if permission cannot be established, omit or fail rather than expose content.
04Build a useful feed with one application
Start with a SQL database containing posts, author timelines and typed relationships. Maya sends a create request with key k91. One transaction saves p882, its author-history entry, the request result and a publication event. The API acknowledges commit. A retry of k91 returns the same p882; success does not claim that every follower already has a prepared feed.
For Leo’s first feed, the application reads his followed sources, retrieves bounded recent posts from their indexed timelines, checks current eligibility and reply rules, sorts by time and returns twenty. This is fanout on read: the application gathers several author histories when the reader asks. The baseline needs no background copies to produce a correct page.
Store the bounded candidate order for the browsing session before returning its cursor. New posts appear on refresh rather than shifting older page positions. Later pages still recheck deletion, blocks and membership. Media bytes stay in the media service; the feed contains authorized references and summaries.
Chronological ordering is a complete initial ranking policy. Personalization can be introduced once candidate retrieval and permission behavior are clear. The first scaling problem is repeatedly collecting and merging similar author histories for millions of readers.
The application gathers recent author histories, checks typed relationships and returns a bounded ordered session.
Read each connection in order
- syncPublish / open / continueAuthor and reader → Post / feed application
- syncCommit or retrieve recent postsPost / feed application → Posts and author timelines
- syncFind sources; check eligibilityPost / feed application → Typed relationships
- syncSave and resume orderPost / feed application → Bounded feed sessions
05Compare repeated reads with recipient writes
Assume 300 million daily active readers, five feed opens per day and 500 followed entities per reader. Use a fivefold peak and twenty stories per page.
| Quantity | Calculation | Meaning |
|---|---|---|
| Feed requests | 300 million × 5 / 86,400 | About 17,361/s average and 86,805/s peak. |
| Naive author retrievals | 17,361 × 500 | About 8.68 million author lookups/s average. |
| Full 500-story copies | 300 million × 500 × 1 KB | 150 TB logical, before replicas. |
| Bare 500-ID lists | 300 million × 500 × 8 B | 1.2 TB before scores, indexes and overhead. |
| Peak summary bytes | 86,805 × 20 × 1 KB | About 1.74 GB/s before photos and video. |
Preparing references can reduce repeated reads, but publication then creates recipient writes. If an ordinary author has 500 followers and 40% are active, one post produces about 200 candidate writes. A twenty-million-follower author with the same active fraction produces eight million. At 40 bytes per candidate entry, that is 320 MB of logical mutations for one publication.
The useful comparison is publication frequency × active recipients × write cost versus actual reader requests × author-merge cost. Follower count alone is a starting heuristic. Audience activity and posting rate can change whether precomputation saves work.
06Define publication, refresh and continuation
First-page request
GET /feed?limit=20&excludeReplies=true
Continuation request
GET /feed?cursor=token
Here token stands for the opaque cursor returned for the browsing session.
| API | Meaning |
|---|---|
POST /posts |
Save one source post using an idempotency key and verified media IDs; return its stable identity. |
GET /feed?limit=20&excludeReplies=true |
Begin a ranked session from current candidates. |
GET /feed?cursor=token |
Continue the same viewer, filters and stored session order. |
PUT or DELETE /following/u17 |
Change the viewer’s distribution interest. |
DELETE /posts/p882 |
Mark the owner’s post deleted and schedule derived cleanup. |
Derive author and viewer identities from authentication. The request key is scoped to the author and payload; changing the payload while reusing it conflicts. Media references must belong to uploads the author is permitted to attach.
Choose a five-minute session lifetime for this exercise. Its opaque cursor binds the viewer, filters, session and next position; another user cannot reuse it. Expiry requires refresh rather than inventing a continuation from newly ranked data. Restrict page size and total session depth.
A new-stories notification is optional and lightweight. Pull-to-refresh remains the complete delivery path if notifications are lost. Precomputing a server-side candidate list while Leo is offline is different from transmitting unseen stories to his phone.
07Make candidate lists disposable, not authoritative
Source records and durable publication work
| Record | Role |
|---|---|
Post |
Holds the source post. |
Indexed AuthorTimeline |
Supports reading an author's post history. |
Follow, Friendship, GroupMembership |
Retain distinct relationship types and their access meaning. |
| Blocks | Record the restrictions applied during eligibility checks. |
| Request identities | Recover the source-post result after a retry. |
| Outbox | Records publication work transactionally so it can be delivered later. |
If the application crashes between committing p882 and sending a queue message, the outbox relay still discovers the pending event.
A candidate stores a reference, not a duplicate body or permission grant.
Candidate field |
Purpose |
|---|---|
viewerId |
Identifies whose candidate list contains the story. |
postId |
Refers to the source post. |
sourceVersion |
Records the source version associated with the candidate. |
createdAt |
Supplies the creation-time value used in ordering. |
Make (viewerId, postId) unique so repeated fanout cannot create duplicate visible slots. Partition candidates by viewer for local retrieval, while author timelines are indexed by author and creation-time/post-ID order.
Maintain both following and follower access paths. Feed reads ask which sources Leo follows; publication asks which active viewers follow Maya. Scanning every viewer on each publication would defeat the intended optimization.
Derived serving state
| State | Stored information | Boundary |
|---|---|---|
FeedSession |
Bounded ordered candidate IDs, ranking version and expiry | Its lifetime is separate from the viewer's reusable candidate cache. |
| Body cache | Content keyed by post ID and content version | Reuses the identified version without becoming the source record. |
Source posts, relationships and durable events support recovery; candidate caches and session lists cannot replace them.
For the chosen one-node-loss target, authoritative post, relationship and publication-event stores acknowledge changes only after durable majority commits across three replicas in independent regional failure domains. Each store must preserve its own acknowledged decisions on failover; this does not create a global transaction across the social graph. Candidate and session views retain their stated rebuild/restart behavior.
08Push ordinary candidates and pull expensive audiences
For ordinary authors, use publication events to insert post references into active followers’ candidate lists. This is fanout on write: the work happens after publication, before those readers request a page. Reads usually need one bounded candidate lookup instead of hundreds of author queries. Keep only a useful recent window, such as 200–500 candidates, and avoid filling unlimited feeds for inactive accounts.
Popular authors whose fanout would dominate writes remain on a pull path. At read time, merge their bounded recent histories with Leo’s prepared ordinary candidates. Deduplicate post IDs because a policy change or overlapping path can temporarily supply the same story twice. This chosen hybrid trades two retrieval paths for manageable celebrity publication cost.
A returning inactive reader may need a bounded rebuild from current relationships and recent author timelines. Let concurrent requests for the same viewer share one rebuild, so ten browser retries do not trigger ten independent scans. Make the slower cold-start behavior visible rather than promising every abandoned cache can be reconstructed instantly.
Fanout workers process one recipient page at a time, write unique candidate entries and save progress only after those writes can be recovered. A crash can replay the page. Indexing an event as consumed before its candidate writes survive can create missing stories. Replica and cache capacity should follow measured candidate writes per consumed story, not only total user count.
09Rank a bounded eligible pool
Collect, for example, 300 ordinary candidates and 100 from pull-only authors. Remove duplicates, filter replies under the request policy and check eligibility. These are illustrative budgets to evaluate. They bound work; they do not guarantee that the globally best story exists inside this retrieved set.
Start with a lightweight score using declared signals such as recency, prior interaction with the author and topic interest. A more advanced ranker can predict outcomes.
Illustrative scoring rule
score = 2 × P(meaningful interaction)
+ 0.5 × P(save)
+ 0.1 × freshness
− P(hide)
P means the predicted probability of that outcome, and freshness is normalized between zero and one. The weights are an illustrative product policy.
| Post | P(interaction) | P(save) | P(hide) | Freshness | Score calculation |
|---|---|---|---|---|---|
p882 |
0.30 | 0.10 | 0.02 | 0.80 | 0.60 + 0.05 + 0.08 − 0.02 = 0.71 |
p883 |
0.15 | 0.40 | 0.01 | 0.90 | 0.30 + 0.20 + 0.09 − 0.01 = 0.58 |
P(interaction) in the table means P(meaningful interaction) from the rule. The first post ranks higher despite being less fresh.
Break ties deterministically and apply simple diversity rules, such as avoiding many consecutive posts from one author. Freeze the resulting bounded order for the session. Evaluate usefulness, unwanted exposure and whether predicted probabilities match observed outcomes; raw engagement alone can reward the wrong behavior.
10Resolve the late-fanout privacy race
A worker reads that Leo follows Maya at relationship version six, then pauses. Leo unfollows her, committing version seven. The worker resumes and inserts p882 into his candidate cache. That insertion is stale but recoverable: the feed service checks current relationships while serving and excludes Maya’s story from this followed-content feed.
The same principle applies to deleted posts, blocks and restricted groups, with their actual permission rules. Removing stale candidate entries asynchronously reduces wasted work; it is not the decisive access check. An unfollow does not make Maya’s otherwise public profile secret, while losing private-group membership can remove permission to read its content at all.
Authorize the exact content version returned. If a check approved public version one, do not fetch and return a later private version two under that old decision. Fetch the approved immutable version or recheck the changed version within a bounded deadline. If current access cannot be established, omit the story or fail rather than return cached text optimistically.
Authorization is a point in the request: a response already authorized before a subsequent revocation may finish. The next serving check observes the change. A stronger barrier that stops every in-flight response is a different contract, not a property supplied by asynchronous invalidation.
The serving check, not candidate membership, decides whether the story belongs in the response.
Read each connection in order
- syncRead follow version 6Fanout worker → Relationship store
- syncCommit unfollow version 7Relationship store → Relationship store
- syncLate candidate p882Fanout worker → Feed service
- syncCheck current relationshipFeed service → Relationship store
- syncVersion 7: exclude storyRelationship store → Feed service
11Recover source-backed views and degrade ranking
A lost candidate cache is not an empty product history. Reconstruct a recent window from durable source posts and current relationships. To avoid missing publications during the scan, record an event-log boundary before rebuilding, replay changes from that boundary and deduplicate before switching to the new list. Detailed multi-partition handoff belongs in the Advanced version, but the need for overlap must be explicit.
If a fanout worker fails halfway through a recipient page, replay its unique viewer/post insertions and then checkpoint. If event processing is behind, show measured freshness degradation, prioritize active readers and bound the queue. A five-minute periodic rebuild by itself cannot meet a five-second new-story target.
If ranking times out, return a bounded chronological page of eligible candidates and identify the fallback. If permission checks fail, that fallback cannot safely reveal uncertain private stories. Lost notifications merely remove the new-stories hint; refresh can still read current state.
Deliver private media through an authenticated media edge that checks access before serving cached bytes. Already downloaded bytes and transfers admitted before a later revocation cannot be recalled. A public long-lived object URL would undermine a correct feed-body permission check.
Publication events prepare ordinary-author candidate lists. The feed service merges those with popular-author histories, checks current relationships, ranks a bounded pool and saves the session order. Later pages use that order but recheck eligibility. Private media is delivered through a separate authenticated edge.
Read each connection in order
- syncPublish / refresh / continueAuthors and readers → Post + feed service
- syncCommit / popular histories / eligibilityPost + feed service → Post histories + relationship stores
- asyncCommitted events and follower pagesPost histories + relationship stores → Outbox relay + fanout workers
- asyncUnique viewer / post insertsOutbox relay + fanout workers → Viewer candidate lists
- syncOrdinary-author candidatesPost + feed service → Viewer candidate lists
- syncSave or resume ranked orderPost + feed service → Bounded ordered feed sessions
- mediaRequest private mediaAuthors and readers → Authenticated media edge
- syncCheck current accessAuthenticated media edge → Post + feed service
- mediaFetch bytes on missAuthenticated media edge → Private media storage
12Check the design against the requirements
Use the agreed lists to check the finished design. The tests below still need to establish the targets; a proposed mechanism is not a measured result. FR refers to the numbered functional requirements above; NFR refers to the numbered non-functional requirements.
| Requirement | Design mechanism | Validation and remaining limit |
|---|---|---|
| FR1–2 + NFR4: source and relationships | Durable source/request/outbox transactions and explicit typed access relations. | Lose a publish response, replay the event and fail one database node. The source post and intended publication work must survive. |
| FR3 + NFR1–3: fast fresh ranked feed | Hybrid fanout/pull, bounded candidate merge and measured ranking. | Benchmark ordinary and celebrity traffic, p95 response and five-second candidate propagation. Retrieval and ranking may omit an available story. |
| FR4 + NFR5: useful continuation | Five-minute stored session order with eligibility checks on each page. | Publish new stories and change permissions between pages; refresh reveals new candidates while ineligible old entries disappear. |
| NFR4,6: honest degraded service | Replay-backed candidate rebuild and chronological ranking fallback. | Lose candidate storage or the scorer; recover without skipping event overlap. A permission outage cannot use the same permissive fallback. |
13Rapid revision
Remember: Prepare candidates to save repeated reads, then check current access; an old candidate list cannot grant permission.
Measure publication-to-eligible-feed delay separately from response latency. Track candidate writes per post, active-recipient fraction, candidates scored per page, duplicate/empty pages, permission-filter rate and cache rebuild cost. At the peak estimate, scoring 500 candidates per request means approximately 43.4 million candidate-viewer scores/s, so bounded pools and staged scoring matter.
| Decision | Benefit | Cost or limit |
|---|---|---|
| Save post and fanout work together | Resume feed preparation after crashes. | Feed propagation remains asynchronous. |
| Copy ordinary-author references to active followers | Avoid recollecting candidates on every read. | Write and retain each selected follower’s reference. |
| Pull high-fanout authors | Avoid millions of unused writes. | Extra read-time merging. |
| Keep a limited ranked list per session | Continue later pages in the same order. | Refresh is needed for newer ranking/stories. |
| Recheck current post version and viewer access | Exclude outdated or inaccessible candidates. | Check relationships and posts; filtering may shorten pages. |
| Chronological ranking fallback | Useful feed during scorer failure. | Does not replace permission checks. |
For a final explanation, follow p882 through committed source state, ordinary fanout or celebrity pull, bounded candidate merge, eligibility and ranking. State that candidate caches are rebuildable views and the product chooses a few seconds of propagation delay. The next tuning decision follows measured audience activity and consumed-story cost, while ranking changes are judged by usefulness and safety rather than engagement alone.
Practise the interview questions
Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.
What are the four responsibilities in a feed?
Reveal a model answer
Publication stores the source, candidate generation finds possible stories, ranking orders them and delivery returns selected authorized content.
Interviewer follow-up
Does a notification make the source durable?
Reveal the follow-up answer
No. It is a hint; durability comes from committed source state.
What the answer must demonstrate: Keeps durability and notifications separate.
Why combine write-time and read-time generation?
Reveal a model answer
Ordinary active audiences benefit from prepared references, while celebrity fanout may create millions of unused writes. Pull those histories during actual reads.
Interviewer follow-up
What decides the threshold?
Reveal the follow-up answer
Posting rate, active audience reads and measured write/merge costs, not follower count alone.
What the answer must demonstrate: Uses audience economics to justify both paths.
Why not represent every relationship as a follow?
Reveal a model answer
Distribution interest, approved friendship and private-group membership grant different behavior and access. A one-way follow cannot silently authorize friends-only content.
Interviewer follow-up
Does unfollowing make a public profile private?
Reveal the follow-up answer
No. It removes that source from this followed-content feed; profile access follows its own policy.
What the answer must demonstrate: Distinguishes distribution from actual access grants.
What if fanout inserts a story after the viewer unfollows?
Reveal a model answer
The late candidate can remain temporarily, but current serving-time relationship checks exclude it. Async cleanup is an optimization.
Interviewer follow-up
What additional check protects edited content?
Reveal the follow-up answer
The returned body must be the exact version that passed the permission check; a newer version needs another check.
What the answer must demonstrate: Checks current eligibility and binds the returned body version.
How can a ranked feed keep page two stable?
Reveal a model answer
Save a bounded ordered candidate session and resume by its cursor, while rechecking current eligibility on each page.
Interviewer follow-up
Where do new stories appear?
Reveal the follow-up answer
On refresh or a new session, optionally announced by a lightweight hint.
What the answer must demonstrate: Freezes bounded order without freezing permissions.
What is the difference between ranking quality and candidate recall?
Reveal a model answer
A ranker can order only retrieved candidates. A useful story excluded by an overly small pool cannot be recovered by a perfect score.
Interviewer follow-up
What should evaluate the scoring objective?
Reveal the follow-up answer
Usefulness, unwanted exposure, diversity and whether predicted probabilities match actual outcomes, not engagement alone.
What the answer must demonstrate: Separates missing candidates from scoring errors.
How do you avoid a gap while rebuilding a lost candidate list?
Reveal a model answer
Record an event boundary before scanning source timelines, then replay overlapping changes and deduplicate before cutover.
Interviewer follow-up
Why is a periodic rebuild insufficient for five-second freshness?
Reveal the follow-up answer
Its interval alone can exceed the freshness target; incremental events are required.
What the answer must demonstrate: Includes overlap/replay rather than scan-only reconstruction.
What can safely degrade during a ranker outage?
Reveal a model answer
Use chronological ordering over bounded eligible candidates. Current permissions and content-version checks remain mandatory.
Interviewer follow-up
What if the graph permission service is unavailable?
Reveal the follow-up answer
Omit uncertain stories or fail; cached public-looking text is not authorization.
What the answer must demonstrate: Degrades ordering without weakening authorization.
Blank-page exercise · 45 minutes
Build the answer yourself
Design a ranked followed-content feed. Trace an ordinary post, a celebrity post, an unfollow racing fanout and a reader continuing page two.
- 0–5 min: agree numbered functional and non-functional requirements for typed relationships, ranked sessions, 300 ms latency, five-second freshness, source durability and privacy.
- 5–12 min: build the SQL baseline and compare read/write costs.
- 12–20 min: define source, outbox, candidate and session records.
- 20–30 min: explain hybrid generation and a bounded ranking example.
- 30–38 min: handle unfollow, content versions, partial fanout and cache loss.
- 38–45 min: review the final design against the numbered FR/NFR lists, test ranked/chronological fallback and privacy, and identify unmeasured latency, freshness and quality targets.
Check that each component and design decision follows from your requirements and workload.
Recall the key ideas
Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.
Design a personalized news feedWhat happens between an author publishing and a reader seeing a ranked page?Recall first, then reveal
Save the post, collect eligible candidates, rank them, then return the page. A saved post alone does not mean a follower has received it.
Store, find, order, return.
Return to lessonDesign a personalized news feedWhy prepare ordinary authors’ entries but fetch celebrity posts when the feed is read?Recall first, then reveal
Preparation saves repeated reads. Pulling celebrity posts avoids writing millions of follower entries that few readers may use.
Push reusable work, pull expensive audiences.
Return to lessonDesign a personalized news feedLeo unfollows Maya while a fanout worker is paused; it later inserts p882. Can the next followed-content feed show it?Recall first, then reveal
No, if unfollow committed before the serving check. Recheck the current relationship and exclude the stale candidate. Ranking or cache membership cannot override that decision.
Candidate does not mean permitted.
Return to lessonFinal revision
Summary and interview notes
Prepare references for ordinary authors and fetch celebrity posts on reads. Check current access, rank a bounded candidate set, and keep that order for the reader’s next pages.
Remember these points
- Commit publication before asynchronous fanout.
- Compare the cost of writing to active followers with the cost of merging author histories during their reads.
- Keep bounded stable page sessions.
- Check the actual follow, friendship or group rule and return only the content version it authorizes.
Interview tips
- Use an unfollow-before-late-insert timeline.
- Compare writes per consumed story rather than total cached users.
Important qualifications
- The design accepts propagation delay and bounded candidate recall.
- Recommendations from unfollowed creators require a separately evaluated candidate source.
Continue after the core interview
Explore the advanced version
The advanced lesson keeps the full detailed design. Use these sections when you want to examine the stronger requirements and failure cases.
- Generation-safe candidate rebuild and cutover
Prove snapshot/log overlap and ownership during concurrent cache reconstruction.
- Authorized hydration and in-flight revocation
Analyze stronger disclosure boundaries and content-version races.
- Fanout strategy migration
Move authors between push and pull paths without missing or duplicating visible stories.
- New retrieval sources and recommendation scope
Extend followed-content retrieval under the same eligibility and candidate budgets.
Technical references
- TAO research paperPrimary description of a large social-graph data service; background for relationship access patterns.
- Kafka designDurable log, consumer progress, and processing semantics underlying reliable incremental publication.
- Meta: News Feed rankingPrimary 2021 explanation of candidate inventory, prediction models, combined ranking scores and contextual diversity; the chapter weights and example values are hypothetical.
Practice marks stay in this browser.