System design guide

Design a social news feed

"Design the Facebook news feed" or "design the Twitter timeline" is a favourite at product-heavy companies because the core trade-off, precomputing feeds versus building them on demand, has no single right answer. This guide shows how to reason through it.

1. Clarify the requirements

Ask: Is the feed chronological or ranked? Text only, or media too? Do we include posts from groups and pages, or only people you follow? How fresh must it be? What's the scale?

Functional requirements

  • Users publish posts (text, images, links).
  • Users see a feed of recent posts from accounts they follow, newest or most relevant first.
  • Infinite scroll with pagination; new posts appear without a full reload.

Non-functional requirements

  • Fast feed loads: p99 under about 200 ms for the first page.
  • Eventual consistency is fine: a post appearing in followers' feeds a few seconds later is acceptable.
  • Highly available; a stale feed is much better than an error.

2. Estimates

QuantityAssumptionResult
Users500M daily active users
Feed reads10 feed loads per user per day5B/day ≈ 60,000/s average, ~150,000/s peak
Posts1 in 5 users posts once a day100M posts/day ≈ 1,200/s
Fan-outAverage 200 followers per poster20B feed inserts/day ≈ 230,000/s
Feed cacheKeep last 500 post IDs × 16 bytes for each DAU500M × 8 KB ≈ 4 TB across a cache cluster

The important number is fan-out: pushing every post into every follower's feed means hundreds of thousands of writes per second on average, and a single celebrity post could mean 100M writes. That shapes the whole design.

3. API

POST /v1/posts               { text, media_ids[] }        → { post_id }
GET  /v1/feed?cursor=&limit=20                              → { items[], next_cursor }
POST /v1/users/{id}/follow

4. High-level architecture

News feed architecture The post service writes posts to the post store and publishes an event to a queue. Fan-out workers read the follower graph and push post IDs into per-user feed caches, skipping celebrity authors. The feed service reads a user's cached feed, merges in recent posts from followed celebrities, ranks, hydrates post content from the post cache, and returns a page. publish load feed write followers push IDs read IDs hydrate + celeb pull Clients Post service Feed service(merge + rank) Post store+ post cache New-post events Fan-out workers Follow graph Feed cache(per-user lists)
Push for normal authors, pull for celebrities, merged and ranked in the feed service.

Publishing. The post service stores the post, then emits an event. Fan-out workers look up the author's followers and prepend the post ID to each follower's feed list in the feed cache. This is asynchronous, so publishing stays fast.

Reading. The feed service reads the user's precomputed list, pulls recent posts from any celebrity accounts they follow, merges, ranks, then hydrates post bodies, author info, and counts from caches.

5. Fan-out on write vs read (the core trade-off)

Fan-out on write (push)Fan-out on read (pull)
Read latencyFast: feed is precomputedSlow: query every followee at read time
Write costOne write per followerOne write total
Celebrity postsMillions of writes per postNo problem
Inactive usersWasted work on feeds no one readsNo wasted work

The standard answer is a hybrid: push for authors under a follower threshold (say 10,000–100,000), pull for authors above it. Also skip pushing to users who haven't logged in for weeks; rebuild their feed on demand when they return.

6. Data model

posts            post_id (snowflake: time-sortable), author_id, text, media[], created_at
follows          follower_id, followee_id, created_at        -- both directions indexed
feed:{user_id}   Redis sorted set: member = post_id, score = rank or timestamp; trimmed to ~500
user_flags       user_id, is_celebrity (derived from follower count)

Time-sortable IDs (Snowflake-style: timestamp + machine + sequence) make "newest first" a cheap ID comparison and give you a natural pagination cursor. Shard posts by post_id and the follow graph by follower_id (for "who do I follow") with a second copy by followee_id (for fan-out).

7. Ranking and scaling

  • Ranking. Start chronological, then describe a two-stage ranker: take a few hundred candidates (pushed feed + celebrity pulls + maybe recommended posts), score them with a model using features like affinity with the author, post age, and engagement so far, and return the top results. Keep the expensive model off the write path.
  • Hydration cost. A page of 20 posts may need 20 post lookups, 20 author lookups, and counts. Batch them (multi-get) and cache aggressively; like/comment counts can be approximate and updated asynchronously.
  • Media. Images and video go to object storage behind a CDN; the feed only carries URLs.
  • Hot partitions. A viral post's like counter is a hot key; shard counters (N sub-counters summed on read) or aggregate in a stream processor.
  • Freshness. Push a lightweight "new posts available" signal over a long-lived connection or let the client poll the head of the feed; don't re-rank the entire feed on every new post.

Failure modes

If the feed cache loses a node, those users' precomputed feeds are gone. Rebuild them lazily on the next request by pulling recent posts from their followees (the same path used for celebrities), and accept a slower first load. If the ranking service is down, fall back to reverse-chronological order rather than failing the request. If post hydration is slow, return the page with the posts you have and let the client fill the rest. In every case, a degraded feed beats an empty one.

8. Trade-offs to call out

  • Precompute vs compute on demand, with the celebrity threshold as the dial.
  • Consistency: deleting a post must remove it everywhere; store IDs in feeds and filter deleted IDs during hydration rather than chasing every copy.
  • Storage vs latency: keeping 500 items per user in memory is several terabytes; trimming to 200 saves memory but makes deep scrolling fall back to slower pulls.
  • Ranking quality vs predictability: users complain about both "I missed posts" and "my feed is stale". Mention a chronological option.

9. Common follow-up questions

  1. A user follows 5,000 accounts. Does pull still work? Pull is only used for celebrities, which are few per user; cap the number merged at read time and lean on the precomputed list.
  2. How do you handle unfollow? Stop future fan-out immediately, and filter that author out during read-time merge until old items age out of the cached list.
  3. How do you add ads or recommended posts? Treat them as additional candidate sources in the ranking stage, with slot rules (for example, at most one ad per five posts).
  4. How would you test a new ranking model? A/B test by user bucket, measuring engagement and also guardrails like hides and reports.
  5. What if the fan-out queue backs up? Feeds get stale but reads still work; prioritise fan-out to recently active users and scale workers on queue lag.

At Meta this exact prompt can come up in either design round; see Meta product architecture vs system design for how the emphasis shifts.

FAQ

Fan-out on write or fan-out on read?

Use a hybrid. Fan-out on write (push) for normal users gives fast reads; fan-out on read (pull) for accounts with millions of followers avoids writing a single post into millions of feeds. Merge the two at read time.

Should the feed store full posts or post IDs?

Store post IDs (plus a score and author ID) in the per-user feed, and hydrate post content from a separate post cache at read time. Edits and deletes then only touch one place.

How do you paginate a feed?

Use cursor-based pagination keyed on the score or timestamp of the last item seen, not offsets. Offsets break when new items arrive at the top while the user is scrolling.