Design Facebook News Feed
Patterns, Technologies, and Concepts
Key Takeaways
Requirements
You demonstrated strong requirements gathering skills for a news feed system, correctly prioritizing availability over consistency and identifying key scalability challenges from the start.
-
For social feed systems, availability beats consistency. Users can tolerate seeing a post 30-60 seconds late, but a feed that fails to load is unacceptable. Frame this as ‘eventual consistency with a bounded staleness window’ to show you understand the tradeoff.
-
A 500ms end-to-end latency target is a strong benchmark for feed generation. This typically means pre-computing feeds asynchronously (fan-out on write) rather than assembling them at read time, so the feed is ready before the user even asks for it.
-
High-follower users (celebrities) and high-following users (power users) are the two classic edge cases in feed systems. Celebrities create fan-out write storms, while power users create expensive read-time feed assembly. Knowing both and having a mitigation strategy (like hybrid fan-out) shows depth.
Core Entities
You demonstrated strong foundational thinking by correctly identifying the core entities and modeling the Follow relationship accurately on your first attempt.
-
Model Follow as its own entity with two foreign keys (follower_id and followee_id) to represent a uni-directional relationship. This lets you query ‘who does user A follow’ and ‘who follows user A’ efficiently, which is the backbone of any news feed system.
-
The three core entities for a news feed are User, Post, and Follow. User stores account data, Post stores content tied to a user, and Follow maps which users subscribe to which other users’ content.
API
You demonstrated solid API design instincts from the start and refined your answers well across attempts, with your main growth area being REST naming conventions for paths and resources.
-
REST paths should represent nouns (resources), not verbs (actions). Instead of /users/[id]/follow, use /users/[id]/followers or /users/[id]/following. This makes the resource hierarchy clear and keeps your API idiomatic.
-
Name feed endpoints explicitly to reflect their purpose. GET /posts is ambiguous because it sounds like it returns all posts globally. GET /feed makes it immediately clear you are returning a personalized feed for the current user.
-
The current user’s identity should come from an auth header like a JWT or session token, not from the request body or URL. This keeps sensitive identity data out of payloads and is the standard pattern for authenticated REST APIs.
High Level Design
You demonstrated strong system design instincts throughout all four sections, consistently choosing clean separations of concern and appropriate data models, with only minor gaps around edge cases and diagram clarity.
-
When building a feed from followed users, the Feed Service needs to fetch posts for each followed user, merge the results into a single list, and sort by timestamp before responding. Without the explicit merge and sort step, the feed has no guaranteed chronological order.
-
Fan out on read (building the feed at read time) gets expensive as follow counts grow because you must query posts for every followed user on each feed request. Mention this tradeoff early and note that fan out on write (pre-computing feeds) is a common alternative for high follow counts.
-
For cursor based pagination on a time ordered feed, use a compound cursor of timestamp plus postId instead of timestamp alone. If two posts share the exact same timestamp, a timestamp only cursor can return duplicates or skip posts because the position is ambiguous.
-
A follow relationship in a social graph is a unidirectional edge, meaning user A following user B does not imply B follows A. Store it as a single row with follower ID and followed ID so the direction is explicit, and add a GSI on the followed ID column to efficiently answer reverse lookups like who follows this user.
Deep Dives
You showed strong progression across multiple attempts, quickly picking up on async fan out, hybrid celebrity handling, and hot key replication, with your main gaps being around proactive detection of hot posts and some schema modeling details.
-
For viral post hot key problems in Redis, do not just add a cache in front of the database. A single cache shard can still get overwhelmed if one post maps to one key. The fix is to replicate the same post under multiple keys using a suffix (e.g. postId:1, postId:2, postId:3) and have the feed service randomly pick one. This spreads read traffic across multiple cache nodes so throughput scales with replica count.
-
To detect a post going viral before it saturates a cache node, track a per-post read counter in Redis and promote the post to replicated caching once it crosses a threshold. Waiting until a cache node is already hot means you are reacting after performance has already degraded. Proactive per-post counting lets you act before the problem hits.
-
A precomputed feed table should store one row per post per user, not a list of post IDs in a single record. In DynamoDB, use userId as the partition key and createdAt as the sort key. This lets you locate a user’s feed in constant time and range-scan by timestamp for pagination. Query with ScanIndexForward=false to return the most recent posts first.
-
For a Redis sorted set used to merge precomputed feed entries with celebrity posts, use timestamp as the score and post ID as the member. This gives you O(log N) inserts and range queries, and naturally handles ordering across two different data sources. Fetch post IDs from the sorted set first, then batch-hydrate full post content from the Posts table to keep the cache lean.