Home › High-Level Design › Design a News Feed
D

Design a News Feed

The home feed you scroll every morning is three hard problems wearing one trench coat.

High-Level DesignHard14 min read

A strong candidate holds all three in their head at once and never lets one win at the silent expense of the others. This question shows up at Meta, Twitter/X, and LinkedIn loops precisely because it forces that juggling act.

If you remember five things

The whole answer in one glance. Everything below is the defense of these five calls.

  1. Reads are 50x writes. That single ratio is the argument for the whole design: do expensive work at write time to make reads nearly free.
  2. Hybrid fan-out. Push posts into follower caches for normal accounts, pull for the few celebrities, and merge both at read time. Each account takes the path it is cheap on.
  3. Two-stage ranking. Cheap materialized scoring at write time, a light re-rank on only the top ~200 candidates at read time. The hot path is lookups and arithmetic, never a model over your whole graph.
  4. Precomputed, capped, rebuildable. Per-user Redis sorted sets capped near 500 IDs, about 2.4 TB total, and derived data that rebuilds from the source of truth on loss.
  5. Availability over consistency. A friend sees a post a few seconds late and nobody files a bug. The site being down is everybody's bug.

1Clarifying the requirements#

The word "feed" hides at least four different systems, and picking the wrong one quietly costs you the interview. Pin down the shape before you draw a single box.

Candidate: When you say news feed, are we talking a social graph like a friends list, or a follow graph like a creator platform? Interviewer: Follow graph. Asymmetric. I can follow you without you following me back. Candidate: Got it. That matters a lot, because it means some accounts have millions of followers. Do we need strict chronological order, or is a ranked feed fine? Interviewer: Ranked. Chronological is a fallback the user can toggle, but the default is ranked by relevance. Candidate: And the feed is text plus images and video? Do we serve the media ourselves? Interviewer: Media goes through a CDN, assume that part is handled. You store references. Candidate: Last one. How fresh does the feed need to be? If I post, when do my followers need to see it? Interviewer: Seconds for normal accounts is great. For huge accounts, a minute or two of delay is acceptable.

Why that last answer is gold. Say it out loud, because it is the whole game.

  • An asymmetric follow graph guarantees a long tail of accounts with tens of millions of followers.
  • A ranked default means I cannot just append to a list and call it done.
  • A one-to-two-minute freshness budget for huge accounts is explicit permission to treat celebrities differently from everyone else.
  • I will cash that permission in during the deep dive. If the answer had been "strict chronological, synchronous, all accounts equal," this becomes a harder and frankly less interesting problem.

Functional requirements

  • A user can publish a post (text, plus optional image or video reference).
  • A user can follow and unfollow other users.
  • A user can fetch their home feed: a ranked, paginated list of recent posts from accounts they follow.
  • A user can like and comment (we track counts, not the full comment tree).
  • The feed supports infinite scroll with stable pagination.

Non-functional requirements

  • Read heavy. Feed reads dwarf writes, so the read path must be fast, p99 under 200 ms.
  • Highly available. A stale feed beats an error page. We trade consistency for availability.
  • Scales to hundreds of millions of users and accounts with tens of millions of followers.
  • Eventually consistent is fine. Seeing a post a few seconds late is acceptable.
From the interviewer's chair

I put a number on the read path (p99 under 200 ms) on purpose, because "fast" is not a design constraint and a number is. Everything downstream (the precompute, the two-stage ranking, the hot-key defenses) exists to protect that 200 ms. If you leave the latency target vague, I cannot tell whether your design actually meets the bar or just sounds like it does.

2Back-of-the-envelope estimation#

Put numbers on it so the design has a spine. Do this early and out loud, because one ratio falls out of it and dictates almost every later decision.

The point of this section

You are not computing storage to three decimals. You are surfacing one load-bearing fact: reads beat writes by about 50 to 1, and the precomputed feed fits in memory. Those two numbers justify doing real work on write to make reads nearly free. Derive them, then move on.

Reads.

  • Assume 300M daily active users, each opening the feed and scrolling about 10 times a day, one page per scroll.
  • 300M x 10 = 3B reads/day.
  • 3B / 86,400 seconds is roughly 35,000 QPS average.
  • Peak is spiky, call it 3x: about 105,000 read QPS at peak.

Writes.

  • Say 10 percent of DAU post each day, averaging 2 posts.
  • 30M x 2 = 60M posts/day.
  • 60M / 86,400 is about 700 QPS average, maybe 2,000 QPS at peak.

The ratio (this is the one that matters).

  • Reads beat writes by roughly 50 to 1.
  • That is the reason I will do real work at write time, even expensive work, as long as it buys a cheaper read.
  • Paying 700 QPS of extra effort to shave work off 35,000 QPS is a trade I take every time.

Storage for posts.

  • Each post row is small if media lives elsewhere: an id, author id, text (~500 bytes), a few references, timestamps, counters. Call it 1 KB.
  • 60M posts/day x 1 KB = 60 GB/day, about 22 TB/year. Fine for a sharded store.

The fan-out storage (the number that decides the model).

  • Precomputing each feed means storing post IDs in per-user lists. Keep the most recent 500 IDs per user, each ID plus a score about 16 bytes.
  • 500 x 16 bytes = 8 KB per user.
  • 300M users x 8 KB = about 2.4 TB for the feed cache. That fits in a Redis cluster across a handful of nodes.
~2.4 TB
The number that decides push is affordablePrecomputed feeds held in RAM for 300M users. Push fan-out only wins if I can actually store the precomputed result in memory, and this says yes. If it had come back at 240 TB, I would have had to rethink push entirely.

Bandwidth on reads.

  • A feed page of 20 posts, maybe 30 KB of JSON after hydration.
  • 105,000 QPS x 30 KB is about 3 GB/s outbound at peak. Media rides the CDN; the JSON is manageable once sharded across the API fleet.

3Core APIs#

Keep the surface small. Everything is behind auth; the user id comes from the token, not the body.

  • Taking the id from the request body is a classic way to let anyone post as anyone, so I never do it.
POST /v1/posts
Authorization: Bearer <token>
Content-Type: application/json

{
  "text": "shipped the thing",
  "media": [{ "type": "image", "ref": "cdn://img/abc123" }]
}
{
  "post_id": "p_8f2a",
  "author_id": "u_1021",
  "created_at": "2026-11-03T09:15:00Z"
}
GET /v1/feed?limit=20&cursor=eyJzIjoxNjk5...
Authorization: Bearer <token>
{
  "items": [
    { "post_id": "p_8f2a", "author_id": "u_1021", "score": 0.91, "created_at": "..." }
  ],
  "next_cursor": "eyJzIjoxNjk4..."
}
POST   /v1/follow      { "target_id": "u_55" }
DELETE /v1/follow       { "target_id": "u_55" }
POST   /v1/posts/p_8f2a/like

Cursor pagination, not offset. This is a deliberate call, not laziness.

  • I encode the score and post id of the last item the client saw, not a numeric offset.
  • Offset pagination breaks the moment new posts arrive at the top, and in a feed they always do: page 2 with offset=20 after three new posts landed shows you items you already saw on page 1.
  • A cursor that says "give me items ranked below this (score, post_id)" is stable against inserts at the head, which is the normal case for a feed.

Idempotent posts. I make POST /v1/posts idempotent on a client-supplied request id in production, so a retry after a flaky network does not double-post. I mention it rather than clutter the example.

4High-level design#

The one sentence I lead with at the whiteboard: split the write path from the read path, and let a fan-out service sit between them pushing posts into per-user feed caches so the read never has to do graph work.

The point of this section

The boxes are table stakes. What earns points is the queue between the Post Service and the fan-out workers. That seam lets a post return the instant it is durable, absorbs spikes, and guarantees a fan-out backlog can never block or drop a write. Draw the spine fast, then defend the seam.

flowchart LR C[Client] --> G[API Gateway] G --> PS[Post Service] G --> FS[Feed Service] G --> GS[Graph Service] PS --> PDB[(Post Store)] PS --> Q[Fanout Queue] Q --> FW[Fanout Workers] GS --> GDB[(Follow Graph)] FW --> GS FW --> FC[(Feed Cache)] FS --> FC FS --> PDB FS --> RANK[Ranking Service]
The whole system at a glance. The seam that matters is the Fanout Queue between the Post Service and the fan-out workers: it lets a post return instantly and stops a fan-out backlog from ever blocking a write.

Write path, left to right.

  • You POST a post.
  • The Post Service writes it to the Post Store (the durable source of truth) and assigns an ID.
  • It drops a message on the fan-out queue.
  • The response returns the instant the post is persisted and the queue has accepted the message, so posting feels snappy.
  • Fan-out workers pull that message asynchronously, ask the Graph Service who follows the author, and push the new post id into each follower's feed list in the Feed Cache. This is the write-time work I promised to pay for, off the critical path.

Read path.

  • You open the app.
  • The Feed Service reads your precomputed list of post ids straight from the Feed Cache.
  • It hands the candidate ids to the Ranking Service for scoring.
  • It hydrates the top ids into full post objects from the Post Store, with a cache in front to absorb the hot ones.
  • Because your list is already in memory, the common read is one cache lookup plus a hydration, not a graph traversal across 2,000 accounts. That is how 35,000 QPS stays under 200 ms.

What this buys and where it breaks.

  • This is pure push fan-out, and it is beautiful until the account with 40 million followers posts.
  • It reads fast and has exactly one giant problem, celebrities, which we fix in the deep dive.

Snowflake IDs.

  • I want post IDs roughly time-sortable, so I get a free chronological ordering and a ranking tie-break without a separate index.
  • A snowflake-style 64-bit ID (timestamp bits, machine bits, sequence) does this and generates at write with no central sequence.
  • The one hazard a senior interviewer pokes: the wall clock. The generator remembers the last timestamp it emitted and refuses to go backward, waiting out NTP drift instead of reissuing an ID. Sequence bits absorb a hot millisecond and roll to the next on exhaustion, so duplicates become structurally impossible.

5Data model#

A few stores, each picked for its access pattern. Posts and the social graph are different beasts, so I do not force them into one database.

Post Store (sharded by post id, so writes spread evenly and no single shard becomes a hot spot just because an author is popular):

Field Type Notes
post_id string (snowflake) Primary key. Time-sortable id, generated at write.
author_id string Who posted. Indexed for author timeline.
text varchar 500 The body. Media lives in a side table.
media_refs json CDN references, not the bytes.
like_count int Denormalized counter, updated async.
comment_count int Same.
created_at timestamp Also derivable from the snowflake id.
  • The author_id index is what makes the celebrity pull path cheap later, so it earns its keep.

Follow graph (its own store; two access patterns point in opposite directions, so I keep two indexes rather than one and a scan):

Field Type Notes
follower_id string Partition key for "who do I follow".
followee_id string Partition key for "who follows me", the fan-out query.
created_at timestamp When the follow happened.
  • The "who follows me" index keyed by followee_id is the one fan-out hammers 60M times a day: for every post, find every follower.
  • The "who do I follow" index keyed by follower_id is what the read path uses to find which celebrities you follow.
  • Each pattern gets its own partition key, so neither is a full scan.

Feed Cache (the precomputed feed, in Redis, a sorted set per user):

Key Type Value Notes
feed:{user_id} sorted set member = post_id, score = rank or time Capped at ~500 entries.
  • Capping near 500 matters more than it looks: nobody scrolls 500 posts back, so storing more is pure waste, and the cap keeps that 2.4 TB number flat instead of growing without bound.
  • When we exceed the cap we trim the lowest-scoring members with a single ZREMRANGEBYRANK, which keeps memory predictable and the working set hot.
  • A Redis sorted set gives ordered reads, idempotent inserts, and cheap trimming in one structure, which is why I reach for it over a plain list.

6Deep dives#

6.1 The fan-out problem: push, pull, and a hybrid#

This is the signature hard part, so I spend the most time here.

  • Pure push breaks on the account with 40 million followers. One write turns into 40 million cache insertions.
  • That one event can stall the queue, blow past write budgets, and delay feeds for everyone behind it in line.
  • If one such account posts during a peak minute, the workers are doing 40M inserts that have nothing to do with the 2,000 QPS of normal writes queued behind them.
  • This is the hot-key, or celebrity, problem and it is the heart of the question.
Pause before you read on: pull fan-out kills the celebrity write explosion outright. So why not just use pull everywhere and be done?
Reveal the answer
Because pull trades a write problem for a worse read problem. A user following 2,000 accounts now does 2,000 lookups and a merge on every single feed fetch. At 105,000 QPS with a p99 target of 200 ms, that is dead on arrival. Reads are 50x writes and the thing we most need to protect, so moving the cost onto the read path is exactly backward. Reaching for the hybrid unprompted is what earns the room.

Pull fan-out (read-time merge) is the opposite extreme.

  • You write the post once and do nothing else.
  • At read time, look up everyone the user follows, grab each person's recent posts, and merge.
  • Zero write amplification, which kills the celebrity problem.
  • But the read is now expensive: 2,000 lookups and a merge per fetch for a user following 2,000 accounts, at 105,000 QPS. That trades a write problem for a read problem, and reads are what we most need to protect.
Default for the many
Push (fan-out on write)
Read cost
Trivial: read one precomputed list.
Write cost
Heavy: one post touches every follower's list.
Best when
Reads dominate and most accounts are normal-sized.
Breaks when
A celebrity posts: one write becomes tens of millions.
Keep for the few
Pull (fan-out on read)
Read cost
Heavy: fetch and merge from everyone you follow.
Write cost
Trivial: store nothing per follower.
Best when
The author has a huge following.
Breaks when
A read-heavy feed makes every load expensive.

So neither extreme wins, and the senior move is to refuse to pick one. I use a hybrid, split by follower count.

  • Normal accounts (under, say, 100k followers): push. When they post, fan out into follower feed caches. Reads stay cheap because the work happened at write time.
  • Celebrity accounts (over 100k followers): do not fan out. Their posts stay in the Post Store, indexed by author, and are pulled at read time.

At read time the Feed Service merges two sources.

  • Your precomputed feed, filled by push from the normal accounts you follow.
  • A fresh pull of recent posts from the handful of celebrities you follow, using that author_id index.
  • The key insight that makes it cheap: almost everyone follows only a few huge accounts, so the pull side is tiny, maybe 5 to 20 lookups, not 2,000.
  • The expensive push is avoided for exactly the accounts that make it expensive, and the expensive pull is avoided for exactly the accounts that make it expensive. Each account takes the path it is cheap on.
sequenceDiagram participant U as User participant FS as Feed Service participant FC as Feed Cache participant GS as Graph Service participant PS as Post Store participant R as Ranking U->>FS: GET feed FS->>FC: read precomputed feed FC-->>FS: post ids from normal accounts FS->>GS: which celebs do I follow GS-->>FS: short celeb list FS->>PS: recent posts by those celebs PS-->>FS: celeb post ids FS->>R: score merged candidates R-->>FS: ranked ids FS->>PS: hydrate top ids PS-->>FS: full posts FS-->>U: ranked feed page
The read path. The precomputed push list and a fresh pull of the few celebrities you follow get merged, scored, then hydrated into full posts in one batch.

The async seam closes the loop with the clarifying questions.

  • The push side fans out asynchronously through the queue. That is precisely why I confirmed up front that a couple of seconds of delay is fine.
  • The write returns the instant the post is durable and the queue message is accepted, so the author never waits on 40 million inserts.
  • If a worker dies mid fan-out, the message is redelivered, so inserts must be idempotent.
  • A sorted set gives that for free: re-adding the same member with ZADD is a no-op on membership, so a redelivered message cannot create duplicates. Say this out loud; it tells the interviewer you have run one of these in production.
Red flag that fails you here

Committing to pure push, feeling clever about cheap reads, then freezing when I say "a celebrity just posted." Reach for the hybrid on your own and justify the threshold in numbers. Candidates who wait to be told about the celebrity case are the ones who have not actually run this system.

6.2 Ranking without wrecking latency#

A ranked feed means I need a score per post, but I will not run a heavy relevance model on 105,000 reads per second across every candidate in every feed.

  • That is the straight road to a 2-second feed and a blown p99.
  • The design problem is getting good ranking while keeping the hot path to lookups and arithmetic.

I split ranking into two stages, and the split is the whole point.

  • Stage one: retrieval and cheap scoring, mostly at write time. When a post fans out, I store it in the sorted set with a score that is mostly recency plus the author's baseline affinity for that follower. That gives a decent default ordering for free, already materialized in Redis, so even if stage two were skipped the feed would be reasonable. This is the 50-to-1 ratio paying off again: compute the base score once at write, read it millions of times.
  • Stage two: a re-rank at read time, only on the top candidates (say 200), never the whole list. The Ranking Service pulls precomputed features (author affinity, your recent engagement, post freshness, early like velocity) and runs a light model to reorder those 200 into the final 20 to 40 you see. Scoring 200 candidates fits the latency budget; scoring your full follow graph does not. The 200 is a knob: bigger means better ranking and slower reads, and I tune it against the p99 budget.
flowchart TD A[Candidate ids from cache plus celeb pull] --> B[Fetch features] B --> C[Light rerank model] C --> D[Top ranked page] B --> E[(Feature Store)]
Two-stage ranking. Merged candidates get flat feature reads from the feature store, a light model reorders them, and only the top page is returned. Nothing heavy runs inline.

The hard rule: the ranking service never computes features inline, it only reads them and multiplies.

  • Features live in a feature store keyed by user id and post id, refreshed by a separate pipeline on its own schedule.
  • Every expensive thing (embedding lookups, engagement aggregates, affinity scores) is precomputed by background jobs and served as a flat read.
  • Keep the hot path to lookup plus arithmetic, and push everything heavy to background jobs. That discipline is what keeps re-ranking 200 candidates well inside the 200 ms budget.

6.3 Hot keys and cache melt#

Even with the hybrid solving the write explosion, a mega viral post is still a hot key on the read side.

  • Ten million people pull the same celebrity post object in the same minute.
  • The one Redis shard holding that post id becomes a hot spot, and a single hot shard can brown out while the other 50 sit idle.
  • Sharding by post id spreads writes evenly but does nothing for a single object everyone wants to read at once.

Three defenses, layered, because no single one is enough.

  • Replicate hot objects. Detect a high read rate on a specific post and copy it into multiple shards or into a local in-process cache on the Feed Service nodes, so load spreads across many servers instead of melting one shard. Detection can be a sampled counter that flags any post crossing a reads-per-second threshold.
  • Short TTL local cache. The post object rarely changes after it is written, so caching it for even 10 seconds on each app server absorbs the storm. Within any 10-second window each of 500 servers hits the origin once and serves the other thousands of requests from memory, cutting origin reads by orders of magnitude.
  • Request coalescing (single-flight). If 5,000 requests for the same post id arrive at once and it is a cache miss, let exactly one request fetch from the store and have the other 4,999 wait on that single in-flight fetch, then all get the one result. This stops a thundering herd from hammering the Post Store the instant a hot entry expires, which is otherwise the exact moment things fall over.

Counters are their own flavor of hot key, handled separately.

  • I do not write every like straight to the post row, because that row becomes a write hot spot the moment a post goes viral: 10,000 likes a second all contending on one row.
  • Instead I buffer increments in Redis, aggregate them, and flush to the Post Store periodically, say every few seconds.
  • The displayed count is approximate for a few seconds, which no human notices on a post with a million likes, and the database is spared a contention meltdown.
  • This is the same availability-over-consistency trade we agreed to up front, applied at the level of a single integer.

7Bottlenecks and trade-offs#

Name what breaks under load and how you defend each call. The trade-offs are where the interview is actually decided.

The fan-out queue is the pressure point on writes.

  • A breaking-news moment where millions post at once can back the queue up and delay fan-out for everyone.
  • Defend it with priority lanes: a user's own post lands in their own feed synchronously, so they always see what they just posted, while fan-out to followers drains at the queue's pace.
  • Followers seeing it a bit late is the exact trade we secured in the clarifying questions, so I am spending a budget I already own.
  • Autoscale workers off queue lag (age of the oldest unprocessed event), not CPU, because the queue backing up is the real signal of pain and CPU can look fine while latency to followers quietly climbs.

The feed cache is the pressure point on reads, and it is not the source of truth.

  • If a Redis node dies, those users' precomputed feeds vanish.
  • That is survivable precisely because the cache is derived data: any feed rebuilds from the follow graph and the Post Store, it is just slower while it warms.
  • So the cache-miss path must genuinely exist and work, as a cold, pull-heavy rebuild that repopulates the sorted set.
  • A feed cache you cannot rebuild from the source of truth is one that pages you at 3 a.m. when a shard fails, and I have been on the wrong end of that.

Push versus pull is a memory-for-latency trade.

  • Pure push costs that 2.4 TB plus heavy write work, but gives sub-millisecond read lookups.
  • Pure pull costs nothing to store but makes every read do graph work.
  • The hybrid spends memory on the many small accounts, where push is cheap per post, and spends read-time work on the few huge accounts, where push would be ruinous.
  • If the interviewer pushes back that 100k followers is arbitrary, I agree completely, and that is the right pushback. It should be a tuned threshold, even a per-account decision, set by measuring an account's actual fan-out cost against the read cost of pulling it, and rebalanced as accounts grow across the line.

Ranking freshness versus latency.

  • The two-stage split means the base score in the sorted set can be stale relative to a post going viral in real time.
  • The read-time re-rank on the top 200 partly fixes this by pulling fresh engagement features, but a post that explodes after it already fell out of your top 200 candidates never reaches stage two and will not resurface.
  • For most feeds that is an acceptable miss.
  • If the product demands catching rising posts, I add a small real-time "rising" candidate source, a short list of posts with surging engagement, injected into the candidate set at read time so a breakout post gets a second chance at your top 200.

Consistency.

  • We chose availability and eventual consistency everywhere, and I want to be honest about the visible effects rather than pretend they do not exist.
  • You might see a post before a friend does. A like count might lag by a few seconds. An unfollow might leave one stale post in your cache until it ages out past the cap.
  • Every one of those is invisible or trivial to a real user, and in exchange the system stays up and fast under spikes that would topple a strictly consistent design.
  • That is the right trade for a feed. It would be the wrong trade for a bank ledger, and naming that boundary is how I show I am choosing the trade, not defaulting into it.

The numbers are the argument; the architecture is just what the numbers made you build.

8Summary#

The decisions that carry this design:

  • Split read and write paths, do expensive work at write time, because reads outnumber writes 50 to 1 and that ratio pays for itself millions of times over.
  • Hybrid fan-out: push for normal accounts into per-user feed caches, pull for celebrities at read time, merge the two. This kills the hot-key write explosion while keeping reads cheap.
  • Precomputed per-user sorted sets in Redis, capped near 500, costing about 2.4 TB total, rebuildable from the source of truth on loss.
  • Two-stage ranking: cheap materialized scoring at write time, a light re-rank on the top ~200 candidates at read time, with features served from a store, never computed inline.
  • Hot-read defenses: local TTL caches, hot-object replication, request coalescing, and buffered counters.
  • Eventual consistency and availability over strict consistency, which is exactly right for a feed and exactly wrong for money.
Follow-ups the interviewer will ask (and your answers)
"A celebrity with 40 million followers posts during peak. Walk me through what happens."
Nothing explodes, because that account is over the push threshold, so we never fan it out. The post lands in the Post Store indexed by author and the write returns immediately. Their followers pick it up on their next read via the pull side of the merge, within the one-to-two-minute budget we agreed on. The 2,000 QPS of normal writes behind it never see 40 million inserts contending for the queue.
"A fan-out worker dies mid-delivery and the message is redelivered. Duplicate in my feed?"
No. The feed is a Redis sorted set, so re-adding the same post id with ZADD is a no-op on membership. Fan-out is at-least-once and the data structure makes the insert idempotent for free, which is exactly why I chose a sorted set over a plain list.
"A post goes viral after it already fell out of my top 200 candidates. How does it resurface?"
With the base design it does not, and for most feeds that miss is acceptable. If the product needs it, I add a small real-time rising candidate source: a short list of posts with surging engagement, injected into the candidate set at read time so a breakout post gets a second chance at stage two ranking.
"A Redis shard holding millions of feeds dies. Now what?"
Those feeds are gone from cache but nothing is lost, because the cache is derived data. The cache-miss path rebuilds any feed from the follow graph plus the Post Store: a cold pull-heavy rebuild that repopulates the sorted set, slower while it warms but correct. That path has to be real and tested, not theoretical, or it pages you the night a shard fails.
"100k followers is an arbitrary threshold. Defend it."
It is arbitrary, and that is the right pushback. It should be tuned, even a per-account decision, set by measuring an account's actual fan-out cost against the read cost of pulling it, and rebalanced as accounts grow across the line. A 120k account that posts weekly is cheaper to push than an 80k account that posts fifty times an hour, so posting rate belongs in the decision too, not just follower count.

What you can now explain in the room

  • Why reads being 50x writes pushes expensive work onto the write path and drives every other choice.
  • Why pure push breaks on celebrities, why pure pull breaks on reads, and how the hybrid gives each account its cheap path.
  • How two-stage ranking gets a relevance model without ever running it over your full follow graph on the hot path.
  • Why the feed cache is derived data, costs about 2.4 TB, and must have a real rebuild path.
  • How to defend a viral post as a read hot key with local TTL caches, replication, and request coalescing.
  • Where eventual consistency is invisible to users and exactly where that trade would be wrong.

For company-specific angles, see our Meta, LinkedIn, and Twitter system design guides.

Get a prep plan built around your Design a News Feed interview

Tell us the role and your interview date. We will send back a dated, day by day plan. Free.

Thanks. Check your inbox, your Design a News Feed prep plan is on the way.