Javathoughts Logo
Javathoughts
Published on
Views

Design a News Feed System Design Interview Guide

Authors
  • avatar
    Name
    Javed Shaikh
    Twitter

← System Design Interview Preparation

This guide walks through Design a News Feed the way you would in a backend or Java interview. The numbers are interview estimates. They help you show your thinking. They are not a production capacity plan.


1. Problem

A news feed shows a user new posts from people they follow, in a useful order, with pagination.

Example:

  • You follow 200 people
  • They post photos and text during the day
  • When you open the app, you see a ranked list: recent, interesting, not already seen

This is the Instagram / Twitter / LinkedIn home timeline problem. It looks simple. The hard part is fan-out: one post from a popular user must reach millions of follower timelines without melting the database.

In this design we are building a system that:

  1. Lets users create posts
  2. Stores a follow graph
  3. Builds a home timeline
  4. Ranks and paginates that timeline

We are not building stories, ads targeting, or a full social network. We are designing post + follow + feed.


2. Functional Requirements / FR

RequirementWhat it means
Create postText, maybe media ids. Owner is the logged-in user.
Follow / unfollowDirected graph: A follows B.
Home feedPosts from people I follow (and maybe my own).
PaginationInfinite scroll with a cursor, not OFFSET 100000.
Ranking basicsRecency plus simple signals (likes, time decay). Not a full ML platform.
Seen / newOptional. Prefer not showing the same post twice in one session.

Out of scope for a 45-minute interview:

  • Full ads auction
  • Live video
  • Detailed privacy graphs beyond public/followers
  • Multi-country ranking models

Ask if the feed is reverse chronological first. Add ranking as a second step. Interviewers like that order.


3. Non-Functional Requirements / NFR

RequirementWhy it matters
Fast feed readsOpening the app is the most common action. Aim for low hundreds of milliseconds.
Write fan-out costCelebrity posts cannot synchronously update 50 million timelines.
High availabilityFeed down means the app feels dead.
Eventual consistencyA post can appear on follower feeds a second later. That is usually fine.
Pagination stabilityNew posts should not shuffle the page the user is staring at too wildly.

A good interview sentence: reads must be precomputed or very well indexed. You cannot join follow-graph × posts on every app open.


4. Back-of-the-Envelope Calculation

Traffic assumptions

  • 500 million users, but 100 million Monthly Active Users
  • 50 million Daily Active Users
  • Each DAU opens the feed 10 times a day → 500 million feed reads / day
  • Each DAU creates 1 post every 2 days → ~25 million posts / day
  • Average user follows 200 people
  • Read/write ratio (feed reads vs posts) ≈ 500M / 25M = 20 : 1

Feed reads dominate. Posts are the expensive write if you fanout on write.

QPS

Feed read QPS:

500,000,000 / 86,400 ≈ 5,800 QPS

Peak 5× → around 30,000 QPS.

Post create QPS:

25,000,000 / 86,400 ≈ 290 QPS

Peak posts ≈ 1,500 QPS.

If we fanout on write to 200 followers on average:

1,500 posts/sec × 200 timeline writes ≈ 300,000 timeline writes/sec at peak

That number is why this problem is famous. Average is fine. Celebrity users are not average.

Storage

Post body ≈ 1 KB (text + metadata; media in object storage)

25,000,000 × 1 KB ≈ 25 GB/day of post rows

One year ≈ 9 TB. Sharded post store is required at this scale. For the interview, say posts in a distributed DB, media in object storage.

Feed store: each timeline entry is postId + authorId + score + time ≈ 64 bytes.

If we keep 500 posts per user inbox for 100 million MAU:

100,000,000 × 500 × 64 bytes ≈ 3.2 TB

Cache the active users’ first page in Redis.

Cache / memory estimate

5 million users online in a peak hour. First page = 20 entries × 64 bytes ≈ 1.3 KB, plus post bodies for those 20 × 1 KB ≈ 20 KB. Round to 25 KB per hot user.

5,000,000 × 25 KB ≈ 125 GB

That is a Redis cluster, not one box. Cache ids + hydrated posts for the first page only.

Server estimate

Feed read service at 2,000 QPS per instance (mostly cache):

30,000 / 2,000 ≈ 15 feed servers

Use ~20. Post service can be a few more. Workers scale with fanout, not with user QPS.

These are interview estimates, not exact production numbers.


5. APIs

Create post

POST /api/posts

{
  "text": "Shipping a URL shortener write-up",
  "mediaIds": []
}

201:

{
  "postId": "p_9k2",
  "userId": "u_42",
  "createdAt": "2026-09-19T08:00:00Z"
}

Follow

POST /api/follows

{ "followeeId": "u_99" }

DELETE /api/follows/u_99 to unfollow.

Home feed

GET /api/feed?cursor=...&limit=20

{
  "items": [
    {
      "postId": "p_9k2",
      "userId": "u_99",
      "text": "Shipping a URL shortener write-up",
      "createdAt": "2026-09-19T08:00:00Z",
      "likeCount": 128
    }
  ],
  "nextCursor": "eyJ0IjoxNzcwMDAwfQ"
}

Use a cursor (timestamp + post id), not offset.

User profile posts

GET /api/users/:id/posts — this is fanout-on-read friendly: one user’s posts, indexed by user id.


6. Data Model

users

user_id, name, created_at. Normal user service.

follows

FieldNotes
follower_idwho follows
followee_idwho is followed
created_at

Indexes: (follower_id) for “who I follow”, (followee_id) for “my followers” (fanout).

posts

FieldNotes
post_idunique
user_idauthor
text
media_ids
created_at
like_countapproximate is fine

Index (user_id, created_at desc) for profile pages.

feed_timeline (inbox)

FieldNotes
owner_idthe reader
post_id
author_id
scoreranking
created_at

Primary pattern: (owner_id, created_at desc) or a Redis list/ZSET per user.

Do not store full post text in every follower inbox. Store ids, then hydrate.


7. High-Level Design

Posts are saved first. A worker then pushes them into follower feeds. Readers load a prebuilt timeline from the feed store and cache.

News Feed architecture

News Feed architectureA new post is saved, then a worker fans it out into follower feeds. Readers hit the feed service, which uses the feed store and cache.post eventtimeline👤User⚙️Post Service🗄️Post DB📩Queue👷Feed Worker🧾Feed Store👤Reader⚙️Feed Service🧠Cache
A new post is saved, then a worker fans it out into follower feeds. Readers hit the feed service, which uses the feed store and cache.

Components:

  • User (writer): publishes a post.
  • Post Service: validates and stores the post. Publishes a PostCreated event.
  • Post DB: source of truth for post bodies.
  • Queue: buffers fanout work so create API stays fast. See Kafka style pipelines.
  • Feed Worker: loads followers, writes timeline entries, skips or special-cases celebrities.
  • Feed Store: per-user inbox (Redis ZSET, Cassandra, etc.).
  • Reader: opens the app.
  • Feed Service: reads inbox ids, hydrates posts, applies light ranking, uses cache for page 1.
  • Cache: hot first pages and hot post bodies.

Create flow:

  1. Save post.
  2. Return 201 quickly.
  3. Emit event.
  4. Worker fans out to follower inboxes (hybrid for celebrities).

Read flow:

  1. Load timeline ids for the user.
  2. Hydrate posts (cache first).
  3. Return page + cursor.

8. Deep Dives

Follow graph

It is directed. A follows B does not mean B follows A.

Keep this store optimized for two queries:

  • Followees of me — mix of fanout-on-read
  • Followers of me — fanout-on-write

Cache follower lists for users who post often, but celebrity follower lists are huge. Do not load 50 million ids into one worker payload. Page through them.

Fanout on write vs fanout on read

Fanout on write (push): when I post, write that post id into each follower’s inbox.

  • Read is fast: just read my inbox
  • Write is heavy for celebrities
  • Storage duplicates ids

Fanout on read (pull): when I open the feed, fetch latest posts from each person I follow and merge.

  • Write is cheap: one post row
  • Read is heavy: 200 user queries and a merge every time
  • Fine for users who follow few people

Hybrid (the interview answer):

  • Regular users: push to follower inboxes
  • Celebrity users (follower count > N, say 1 million): do not push. Readers pull that celebrity’s latest posts and merge them in at read time

This is the celebrity user problem.

Feed generation

Worker pseudologic:

  1. Read PostCreated
  2. Get author follower count
  3. If celebrity, stop (or write to a “celebrity posts” store)
  4. Else page through followers and batch-insert timeline ids
  5. Trim each inbox to last 500–1000 posts
  6. Invalidate that user’s feed cache if they are online

Use a queue so a slow fanout cannot block posting.

Timeline storage

Redis ZSET: feed:{userId} score = timestamp or rank score, member = postId. Very fast for page 1. Memory-heavy. Often used for online users only.

Cassandra / Dynamo: partition by owner_id, sort by time. Cheaper for the long tail of inactive users.

A common split: Redis for hot users, disk KV for cold inboxes.

Ranking basics

Do not claim a neural net in 45 minutes.

Simple score:

score = time_decay + 0.001 * likes + 0.01 * comments

Time decay keeps the feed fresh. Likes push good posts up a little.

You can rank at write (score stored on the inbox entry) or at read (fetch 2 pages, sort, return 1). Read-time rank is more flexible. Write-time rank is cheaper at 30k QPS.

For interviews: generate a reverse-chronological inbox, then apply a light rank on the latest K items.

Celebrity user problem

If a user has 50 million followers, fanout-on-write is 50 million inbox writes. That can take minutes and flood the cluster.

Treat them as broadcast:

  • Store their posts in a celebrity timeline
  • At read, merge my inbox + latest posts from celebrities I follow
  • Cache celebrity latest posts heavily

Also rate-limit how often a celebrity can trigger notifications. The feed can still show the post.

Hydration

Inbox has ids. Feed service batches MGET post:id1, post:id2, ... from cache, then DB for misses. Never N+1 query each post.


9. Bottlenecks

BottleneckWhat happensWhat you do
Celebrity fanoutQueue lag, worker lagHybrid push/pull
Feed QPSApp open storm in the eveningCache page 1. More feed servers.
Hydration20 posts × DB round tripsBatch + cache post bodies
Follow graph hot readPopular user posts, workers stampede the follow tableCache sharded follower lists
Inbox trimUnbounded Redis memoryCap 500–1000 items
Ranking on full historyToo slowRank only the candidate set

The first bottleneck to name is fanout for popular users.


10. Tradeoffs

Push vs pull vs hybrid

  • Push: great reads, painful celebrity writes
  • Pull: great writes, painful reads
  • Hybrid: extra merge logic, best practical answer

Precompute vs compute on read

Precompute (inbox) costs storage and workers. Compute on read costs latency. At large DAU, precompute the normal case.

Strong vs eventual consistency

Followers can see a post a few seconds late. After you post, you should see it on your profile immediately from Post DB, even if fanout lags.

SQL vs wide-column for inboxes

SQL is fine for a small app. At this scale, interviewers expect Redis/Cassandra for timelines and a normal DB for posts.


11. Failure Modes

Fanout queue down
Users can still post (if Post DB is up). Feeds lag. Show the author’s own post from Post DB. Replay the queue later.

Feed store down
Fall back to fanout-on-read for a degraded feed: last 20 followees only, or a cached copy.

Duplicate posts in feed
Worker retries. Use post_id uniqueness per inbox. Idempotent writes.

Unfollow still showing posts
Delete that author’s entries from the inbox asynchronously. Until then, filter at read time by current follow set for the first page.

Hot celebrity merge slow
Cache celebrity recent posts. Limit how many celebrities you merge (people rarely follow 500 celebrities).

Pagination jumping
Use cursors. Do not use offset. New posts appear on a refresh, not in the middle of an old page.


12. Interview Answer in 10 Minutes

Here is a version you can speak out loud.

"I would design a news feed as a read-heavy system with a hybrid fanout.

Assume 50 million daily users, 10 feed opens each, and 25 million posts a day. Feed reads are about 5,800 QPS, around 30,000 at peak. Posts are only a few hundred QPS, but if I push each post to 200 followers, peak timeline writes can hit hundreds of thousands per second. Celebrity users make that much worse, so I will not push to every follower for them.

Posts go to a post service and post DB. A Kafka-style queue carries PostCreated events. Workers write post ids into each regular follower’s inbox, a Redis ZSET or Cassandra timeline, trimmed to a few hundred entries. Celebrity posts stay on the author’s timeline and are merged at read time.

When a reader opens the app, the feed service loads their inbox, hydrates post bodies from cache, merges a few celebrity posts, applies a simple recency-plus-likes rank on the candidate set, and returns a cursor page.

If the queue is slow, posting still works and feeds catch up. If cache misses, we batch-load the post DB. The create API never waits on 50 million inbox writes.

That is the design: post store, follow graph, hybrid fanout, inbox + cache, light ranking."

Practice this until it is under 10 minutes.


13. Interview Talking Points

  • Do not join follows and posts on every read at scale.
  • Hybrid fanout is the celebrity answer.
  • Async workers keep POST /posts fast.
  • Store ids in the inbox, hydrate in batch.
  • Cursor pagination.
  • Light ranking on a candidate set, not the whole history.
  • Cache page 1 for online users.
  • Event-driven fanout fits event-driven architecture.

14. Follow-up Questions

How do you handle 50 million followers?
Do not fanout-on-write. Pull celebrity posts at read time and cache them.

How do you rank without ML?
Time decay + social proof on the latest K posts. Mention ML as a later ranking service.

What if I unfollow someone?
Filter on read immediately. Clean inbox in the background.

How do media uploads work?
Upload to object storage first, then create post with media ids. Feed stores ids, not bytes.

Can this run on Spring Boot + Kafka?
Yes: post API in Spring, Kafka for PostCreated, consumers write inboxes. See scaling Java event-driven systems.

Other probes: mute words, seen-state, and multi-device pagination.


Related JavaThoughts reading:


Next in this series: Design a Chat Messaging System.