Overview
A social media feed displays posts from users you follow, ordered by relevance or time.
Requirements
Functional:
- Users can follow/unfollow others.
- Users post messages.
- Users see a feed of posts from people they follow.
- Feed sorted by timestamp (latest first).
Non-functional:
- Scalable to millions of users and posts.
- Low latency feed retrieval.

Core Concepts
- Data Model:
Entity | Fields |
---|---|
User | user_id, name, … |
Post | post_id, user_id, content, timestamp |
Follow | follower_id, followee_id |
- Feed Generation:
Two approaches:
- Fan-out on write: When a user posts, push the post to followers’ feeds. Good for small follower counts.
- Fan-out on read: On feed request, fetch latest posts from all followed users and merge. Good for large follower counts.
Simplified Python Example using fan-out-on-read (in-memory)
Step 1: Setup
JavaScript
from flask import Flask, request, jsonify
from collections import defaultdict
import time
app = Flask(__name__)
# In-memory data stores
users = set()
posts = defaultdict(list) # user_id -> list of (timestamp, post)
follows = defaultdict(set) # follower_id -> set of followee_ids
Step 2: Create user & follow/unfollow
JavaScript
@app.route('/user', methods=['POST'])
def create_user():
user_id = request.json.get('user_id')
if not user_id or user_id in users:
return jsonify({'error': 'Invalid or existing user_id'}), 400
users.add(user_id)
return jsonify({'message': f'User {user_id} created'}), 201
@app.route('/follow', methods=['POST'])
def follow_user():
follower = request.json.get('follower')
followee = request.json.get('followee')
if follower not in users or followee not in users:
return jsonify({'error': 'Invalid users'}), 400
follows[follower].add(followee)
return jsonify({'message': f'{follower} followed {followee}'}), 200
@app.route('/unfollow', methods=['POST'])
def unfollow_user():
follower = request.json.get('follower')
followee = request.json.get('followee')
if follower not in users or followee not in users:
return jsonify({'error': 'Invalid users'}), 400
follows[follower].discard(followee)
return jsonify({'message': f'{follower} unfollowed {followee}'}), 200
Step 3: Post creation
JavaScript
@app.route('/post', methods=['POST'])
def create_post():
user_id = request.json.get('user_id')
content = request.json.get('content')
if user_id not in users or not content:
return jsonify({'error': 'Invalid user or content'}), 400
timestamp = time.time()
posts[user_id].append((timestamp, content))
return jsonify({'message': 'Post created'}), 201
Step 4: Fetch feed (fan-out-on-read)
JavaScript
@app.route('/feed/<user_id>', methods=['GET'])
def get_feed(user_id):
if user_id not in users:
return jsonify({'error': 'User not found'}), 404
followees = follows[user_id]
feed_items = []
# Fetch last 10 posts from each followee
for f_id in followees:
user_posts = posts[f_id][-10:] # last 10 posts
feed_items.extend([(f_id, ts, content) for ts, content in user_posts])
# Sort all posts by timestamp descending
feed_items.sort(key=lambda x: x[1], reverse=True)
# Limit feed size
feed_items = feed_items[:20]
# Format feed
feed = [{'user_id': u, 'timestamp': ts, 'content': c} for u, ts, c in feed_items]
return jsonify({'feed': feed}), 200
Step 5: Run the app
JavaScript
if __name__ == '__main__':
app.run(debug=True)
Usage Example
- Create users Alice and Bob.
- Alice follows Bob.
- Bob posts a message.
- Alice fetches her feed and sees Bob’s post.
Limitations & Improvements
- In-memory data won’t scale for real systems; use DB like Cassandra or DynamoDB.
- Fan-out-on-read can be slow if user follows many accounts; fan-out-on-write or hybrid approaches help.
- Add pagination for feed.
- Add caching (Redis) for faster feed retrieval.
- Use background workers for fan-out-on-write feeds.
- Add ranking and filtering (e.g., relevance, promoted posts).