Skip to main content

System Design Questions

Design Hacker News — System Design Interview Guide

Design Hacker News is a system-design interview that asks you to build a community link-sharing site: users post URLs with titles, others upvote and comment, and a ranked front page surfaces the best stories. The hard part is the ranking formula and serving the front page under burst traffic from popular posts.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Reported in interviews at

  • Y Combinator (Hacker News)
  • Reddit
  • Stack Overflow
  • Pinterest
  • Twitter/X

Sourced from Glassdoor, Levels.fyi, and Blind interview reports.

Functional requirements

  • Submit a story (URL plus title, or text-only Ask/Show post)
  • Upvote or flag a story or comment
  • Comment in nested threads on any story
  • View the front page (ranked) and a 'new' page (newest-first)
  • Search stories and comments by keyword
  • User profile pages with submission and comment history plus karma

Non-functional requirements

  • Scale: ~10M MAU, ~5M registered users, ~10K new stories/day, ~100K new comments/day
  • Front-page latency: <200ms p99 (front page is the most-loaded page on the site)
  • Read-heavy: ~10000:1 reads to writes (front-page views >> submissions)
  • Availability: 99.95%; correct ranking matters more than millisecond freshness
  • Burst capacity: a single viral story can drive 100x normal traffic for hours

Capacity estimation

Public scale anchors (HN-style community sites): ~5-10M MAU, ~10K stories/day, ~100K comments/day. Writes are negligible — ~1 story write/sec peak. Reads are huge — front-page is loaded ~100M times/day = ~1.2K/sec average, ~10K/sec peak. Story-detail pages add another ~50M views/day. Total read QPS during peak: ~15-20K/sec.

Storage: stories are tiny — ~500 bytes/row (title, URL, author, timestamps, vote count, score). At 10K/day × 10 years = ~40M total stories = ~20 GB. Comments are larger — average ~500 bytes including the threading metadata. 100K/day × 10 years = ~400M comments = ~200 GB. Both fit comfortably in a single sharded relational instance.

Votes: ~1M votes/day across stories and comments × 32 bytes = ~30 MB/day = ~10 GB/year. Karma is a denormalized counter per user. Comment trees are deep — average ~5 levels with a long tail of 20+ level threads.

The real capacity challenge isn't volume; it's serving the front page under burst load. A linked-from-the-front-page story can drive 100x normal traffic to its detail page, and the front page itself can be hammered when major news breaks. Edge caching with short TTLs is mandatory.

High-level design

The architecture is intentionally simple — this is a small-data problem dominated by caching and ranking.

Write path: submission service writes story or comment rows to a sharded relational store. Comments are parented to either a story or another comment via a parent_id column; the resulting tree is denormalized later for fast tree-reads. Vote service records each (user_id, content_id, vote_type) edge in a separate sharded store; on vote, an asynchronous worker recomputes the affected content's score.

Read path: the front page is a precomputed sorted list of the top ~500 story IDs by score, refreshed every minute by a ranking worker that scans all 'active' stories (typically the ~5K stories submitted in the last 48 hours). The sorted list is held in an in-memory cache and is the response body for the front-page endpoint. Front-page requests don't hit the relational store; they hit the cached list, fetch the 30 story rows for the visible page, and render.

Story-detail pages load the story row plus the full comment tree for that story. The comment tree is denormalized: for each story, store an in-memory cache entry containing the entire serialized comment thread (sorted by score, with reply-nesting structure). Updates to the comment tree (new reply, new vote) invalidate the cache entry, which is rebuilt on the next read. Most stories have <100 comments, so the cached tree is small (typically <50 KB).

Search is the lightest-weight piece: an inverted index over story titles and comment bodies. At ~40M total stories the index is small enough to fit on a single node, and query QPS is low (<100/sec) so a single search node with a replica handles all traffic.

Edge cache fronts everything. Front-page cache TTL is short (~30 seconds — the ranking changes that fast). Story-detail TTL is longer (~5 minutes for old stories, ~30 seconds for fresh ones) keyed on (story_id, comment_version).

Deep dive — the hard problem

Two deep dives: the ranking formula and burst traffic on viral stories.

Ranking formula: a pure upvote count produces a static front page where old stories with thousands of votes outrank everything. The HN-style ranking formula combines upvote count with time decay: score = (upvotes - 1) / (age_in_hours + 2)^1.8. The decay exponent (~1.8) is tuned so a story drops off the front page within ~24 hours regardless of votes; the +2 hour offset prevents brand-new submissions from dominating before they've had time to accumulate signal.

This formula is the heart of the system. Discuss the tradeoffs: a larger exponent means faster decay (more newness, less aggregated quality); a smaller exponent means slower decay (the front page becomes 'best of the week' instead of 'best right now'). Most HN-style sites stick close to 1.8 because empirically it produces a front page that turns over once per ~24 hours.

Additional signal layers usually augment the base formula: flag-based moderation downweights stories that accumulate too many flags; an editorial team can pin or boost specific stories; spam filters demote known low-quality submitters. Avoid drilling into ML re-ranking — most HN-style sites deliberately keep ranking transparent and simple to preserve community trust.

Burst traffic: when a story hits the front page, traffic to its detail page can spike 100x in 5 minutes and stay elevated for hours. Without aggressive caching the relational store would saturate. The cached comment tree per story is the central defense: even at 10K reqs/sec to a hot detail page, the cached tree absorbs all of it; the relational store sees only the writes (votes and new comments).

For the front page itself, edge caching with short TTLs (30 seconds) means at most ~30K cache misses/sec at the edge during a peak — well within capacity of a small fleet. The cache key includes the user_id only for logged-in personalizations (which on HN-style sites are minimal — just 'hide flagged stories' and 'show comments from blocked users'); the vast majority of front-page requests share a single cache entry.

Third tradeoff: comment-tree update propagation. A new comment on a hot story needs to appear quickly. Two options: invalidate the cached tree on every comment write (simple, causes cache thrash during a comment storm) or use a 'version cursor' where the cached tree stores its computation timestamp, and clients fetch a tail of newer comments on top. Most production HN-style sites use the simple invalidation path because the comment-storm case (>10 comments/minute on one story) is rare.

Fourth tradeoff: vote idempotency and gaming. Each user can vote on a story at most once. Storing (user_id, content_id) as the primary key enforces this. Detecting vote manipulation (sockpuppet accounts brigading a story) requires offline analysis — typical defenses include rate limiting by account age, requiring minimum karma to vote, and flagging coordinated voting patterns. Mention but don't drill in.

Common mistakes

  • Storing the comment tree as recursive relational rows and querying it with a recursive CTE at read time — works at 1K stories, dies at burst load
  • Using pure upvote count for front-page ranking — produces a static page where old stories dominate
  • Forgetting edge caching for the front page — it's the most-loaded page on the site and trivially cacheable
  • Designing vote writes synchronously with score recomputation — burst voting on a viral story would amplify into a write hotspot
  • Treating burst traffic as a future-problem — the entire architecture pivots on serving a viral story without degradation

Likely follow-up questions

  • How would you support real-time updates so users see new comments appear without reloading?
  • What changes if karma counts had to be exact in real-time (e.g. for a leaderboard)?
  • How would you detect and rate-limit a brigading attack where many accounts coordinate to upvote a low-quality story?
  • How would you support nested comment threads 50+ levels deep without a recursive query timing out?
  • How would you migrate from a single ranking algorithm to A/B testing multiple ranking formulas in production?

Practice Design Hacker News live with an AI interviewer

Free, no sign-up required. Get real-time feedback on your design.

Practice these live

Frequently asked questions

Why is Design Hacker News asked in interviews?
It's a focused ranking + caching problem with small data, which makes it ideal for a 45-minute interview that probes algorithmic intuition without requiring sharding heroics. Common at mid-level signal-the-fundamentals rounds.
How long is the Design Hacker News interview?
30-45 minutes typical, sometimes used as a warm-up before a harder problem. The expectation is a clean ranking formula and a defensible cache strategy.
Do I need to derive the ranking formula's constants?
No. Stating 'score equals upvotes divided by age raised to some exponent around 1.8, plus an offset to dampen brand-new submissions' is fully credit-worthy. Derivation is overkill.
Should I cover spam/abuse defense in 45 minutes?
Briefly — mention flagging, rate limits by account age, and karma thresholds. Drilling into ML moderation eats time you need for the ranking and cache discussion, which are the load-bearing parts.