SDSystem design
Start learning free

LESSON 46 OF 140 · DESIGN: SOCIAL & FEEDS

SYSTEM DESIGN · INTERVIEW WALKTHROUGH

Design Reddit: System Design Interview, Step by Step

What the interviewer is asking

"Design Reddit" sounds like "design Twitter", but the feed works differently. Twitter's home timeline is built from the people you follow. Reddit's page belongs to a community (a subreddit such as r/cats): everyone who opens it sees the same list, ranked by votes and age. And under each post sits a tree of comments that can hold tens of thousands of replies.

It checks how you rank a list that changes every second, count votes without slowing anyone down, and load a deep thread. The walkthrough follows the 8 steps of the interview framework: scope, data, API, the busy path, numbers, services, scale and deep dives.

1. Scope: what version 1 must do

  • Communities, and posting a link or text to one.
  • Voting posts and comments up or down.
  • A community's page, ranked hot (votes and age), new (time) or top (votes).
  • Nested comments: read them and reply in threads.

Name the rest and park it, one line each: moderator tools, awards, chat, recommendations and search. Each is a system of its own, and the loop of posting, voting and reading works without them.

2. Data: posts, votes and comments

record   fields
post     id, community, author, title, score, created_at
vote     (user, post) → +1 or −1
comment  id, post, parent_id, author, text, score

The score (ups minus downs) is a copy kept on the post: it could be recounted from the votes, but every page view would pay for it. A vote is one row per user and post, so the key itself allows one vote per person (as in the Interview Framework lesson); comment votes work the same way. A comment's parent_id is the comment it answers, empty for a reply to the post itself: that one column is the whole tree.

Two indexes matter (the Indexes lesson): comments by post, so one query finds a whole thread, and posts by (community, created_at), so the "new" page reads the newest 25 directly.

3. The API: four calls

GET  /r/cats/hot?after=…          → 200 OK  25 posts, hottest first
POST /posts/p3/vote  {"dir": 1}   → 200 OK
GET  /posts/p3/comments           → 200 OK  the comment tree
POST /comments  {"post": "p3", "parent": "c2", "text": "…"}  → 201 Created

A vote carries a direction: 1 for up, −1 for down, 0 to take it back. The server knows the voter from the sign-in and works out the score. Sending the new score instead (PUT /posts/p3) loses a vote when two people vote at once and lets anyone send any number; voting with a GET is worse, since browsers, caches and link previews repeat or prefetch GETs.

4. The busy path: reading a hot page

People read far more than they vote, and vote far more than they post. In the simplest design, every view of r/cats does this:

  1. Read r/cats' posts from the last few days.
  2. Work out each one's hot score from its votes and age.
  3. Sort them, hottest first.
  4. Send back the first 25 and an after cursor.

That's hundreds of rows sorted to send the same 25 the last viewer got. Reading a post's comments is the other half of the busy path.

5. The numbers

Numbers from the interviewer: 50 million daily users, about 20 page views each a day, one vote for every 10 page views, and say 1 million new posts a day. A day has 86,400 seconds; round it to 100,000 for quick math.

  • Page views: 50 million × 20 = 1 billion a day ≈ 10,000 a second (about 11,600 with 86,400).
  • Votes: 100 million a day ≈ 1,000 a second (about 1,160 exactly).
  • New posts: 1 million a day ≈ 10 a second.
  • Busy hours: about 5× the average: 50,000 page views and 5,000 votes a second.

That's 10 page views per vote and 100 votes per new post: reads drive the design. And a popular post can collect 50,000 comments.

6. Services: answer now, rank later

Every call reaches a pool of stateless API servers. A vote changes three things: the voter's vote row, the post's score and the post's place on the hot list. Only the row must be saved before the answer: her arrow must stay lit when she reloads, and the row is what keeps her to one vote.

The rest can lag. The API server puts the change on a vote queue and answers; a ranker job takes votes off it, adds them to scores many at a time (batching, as in the Distributed Counter lesson) and re-ranks.

7. Scale: hot lists in a cache

At busy hours, 50,000 page views a second would each read and sort hundreds of posts. Say one database server answers about 5,000 simple lookups a second: it's asked for 10× that, and every ask is heavy. Read replicas would still sort on every view; more API servers would wait on the same database.

Instead, keep each community's hot list ready in a cache: its top 1,000 post ids in hot order. A page view reads 25 ids from memory (one cache server answers about 100,000 reads a second) and fetches those posts by id, cached too. The ranker sorts each community once instead of once per viewer, and the lists are small: say 100,000 active communities × 1,000 ids × 8 bytes ≈ 800 MB. A busy post's comment page can be built once and cached the same way.

8. Deep dive: hot ranking

A common design, close to the formula in Reddit's old open-source code:

hot = sign × log10(max(|ups − downs|, 1)) − age in hours ÷ 12.5

The log counts the zeros: 10 votes give 1 point, 100 give 2, 1,000 give 3. Each 12.5 hours of age takes a point away, the same as dividing the votes by 10, so a post 12.5 hours old needs 1,000 votes to tie a brand-new post with 100. More downs than ups make the votes part negative. Reddit's code counts time from a fixed date instead of age (seconds ÷ 45,000, which is 12.5 hours); the order comes out the same.

Run it on a tiny r/cats at 10:00:

post  votes   age       votes part  age part  hot
p1    10,000  50 h      4           4         0
p2    1,000   20 h      3           1.6       1.4
p3    100     5 h       2           0.4       1.6
p4    10      just now  1           0         1
p5    1,000   10 h      3           0.8       2.2

The hot order is p5, p3, p2, p4, p1. The top sort (votes alone) would put p1 first, the new sort p4. Hot sits between: plenty of votes from the last few hours wins.

How fresh must the list be?

Rebuilding on every view brings back 50,000 sorts a second; rebuilding once a day leaves the page on old posts for hours. About once a minute, for communities that got new votes, is the middle: even all 100,000 communities once a minute is about 1,700 rebuilds a second, and nobody notices a list a minute old. A neat property helps: age lowers every post by the same amount, so the order only changes when votes arrive.

9. Deep dive: votes

Because a vote is a row keyed by (user, post), the server applies new − old. If p3's score is 100 and Ana switches her up vote to down, the score moves by −1 − (+1) = −2, to 98. A repeated tap adds 0, and taking a vote back moves the score by 1.

Then decide what must be exact. Exact, right away: what a person checks about their own action, such as Ana's arrow staying lit and her old vote when she changes it; both come from her own row. Close enough: totals many people glance at, such as the score everyone else sees, the post's place on the hot page and the comment count. Reddit itself says the vote totals it shows are fuzzed a little, to confuse spam bots.

10. Deep dive: nested comments

Loading the tree the naive way, top-level comments first, then each one's replies, then theirs, costs one query per comment: 50,000 queries at about 0.5 ms a round trip is 25 seconds for one page. One document holding the whole tree is no better: each reply rewrites about 25 MB (at 500 bytes a comment), and two replies saved at the same moment overwrite each other.

Instead, load every comment of the post in one query and hang each one on its parent in memory, in one pass. Another option is a materialized path: each comment stores its path, like c2/c5/c8, so one query on the prefix c2/ loads a single thread.

The page shows each reply under its parent, siblings by score, and only the best few per level, with "load more" for the rest. With the best 2 per level, p3's 8 comments show as:

comment and score
c2  +120
  c5  +45
    c8  +12
  c4  +30
c1  +50
  c7  +9
behind load more: c3 +8, c6 +2

One flat list sorted by score would break the threads: c5 and c4 would show under c1, which they don't answer.

11. Deep dive: paging a ranked list

Say pages of 2: Ana reads p5 and p3 from the 10:00 list. At 10:01 the ranker rebuilds it, and p4, after a burst of votes, jumps to the top:

time   hot list
10:00  p5  p3  p2  p4  p1
10:01  p4  p5  p3  p2  p1
  • page=2 (posts 3 and 4 of the newest list) shows p3 again: an offset repeats posts whenever scores change.
  • after=p3 on the newest list gives p2 and p1: p4 moved above p3, so Ana never sees it.
  • A cursor naming the 10:00 snapshot and her place in it gives p2 and p4: no repeat, no skip.

So the ranker keeps each rebuilt list for a few minutes, and after=… carries an opaque token holding the snapshot and the position: the Pagination lesson's cursor, pointed at a snapshot.

What breaks first

  • A viral post: thousands of votes a second on one row; the queue and batching absorb them.
  • The posts database: 1 million posts and 100 million votes a day add up. Shard by post id, with each post's votes and comments on its shard.
  • A huge community's hot list: keep copies on several cache servers.

Summary: the order to follow

  1. Scope: communities, posts, votes, hot, new and top pages, nested comments.
  2. Data: posts with a ready score, one vote row per (user, post), comments with a parent_id.
  3. API: GET /r/{community}/hot?after=…, POST /posts/{id}/vote, GET /posts/{id}/comments, POST /comments.
  4. Busy path: reading hot pages and comment pages.
  5. Numbers: about 10,000 page views and 1,000 votes a second; 50,000 and 5,000 at busy hours.
  6. Services: stateless API servers; a vote queue feeding a ranker job.
  7. Scale: each community's top 1,000 hot ids ready in a cache, about 800 MB.
  8. Deep dives: the hot formula, rebuilt about once a minute; votes as new − old; comments in one query, built in memory; cursors into a snapshot.

The same steps work for any ranked page: compute the ranking in the background and serve it ready from memory.

Keep going with system designInteractive lessons from the building blocks to Twitter, Uber and payments, the way interviews ask. Free to start.
Start learning free