The Four Lines of Code That Run Hacker News
Hacker News sorts every story with one power law: (points - 1) / (hours + 2)^1.8. Here's why it works — and how to steal it for your own feeds.
A 2013 teardown of the Hacker News ranking algorithm is on Hacker News's front page today with 172 points, explaining how Hacker News's front page works. Perfectly recursive. Ken Shirriff reverse-engineered the whole thing by watching scores move — and it turns out every story you've ever upvoted was sorted by one division and one exponent.
The formula fits in a tweet. The interesting part is everything hiding around it.
Why this matters
Someday you will build a ranked feed — trending items, an activity list, search results where freshness matters. HN's algorithm is the cleanest production example I know, because it also shows the part tutorials skip: how to stop bad actors from farming your front page.
How it works
The core score is a power-law decay:
score = (points - 1) / (hours + 2) ** 1.8Every constant is a deliberate decision. The - 1 cancels the submitter's automatic self-upvote, so posting alone scores zero. The + 2 means a story's effective age never starts at zero, which stops brand-new submissions from spiking straight to the top.
The exponent — "gravity" — controls churn. Holding the same score at hour 10 takes roughly 12× the votes it took at hour 1. Nudge that number and the front page turns over faster or slower; HN picked 1.8 as the compromise.
Then come the multipliers. Shirriff found controversial stories — high comment-to-vote ratio, the flame-war signature — get dinged by roughly a factor of 0.4. Votes from brand-new accounts count less. Votes from accounts that always vote together count less. That's the anti-gaming layer: demotion instead of deletion.
Where this helps
- Trending lists. Any "hot" endpoint. Power-law decay beats naive recency sorting because popular items earn the right to linger.
- Search freshness. Multiply relevance score by a decay function instead of filtering by date — the same pattern Elasticsearch's
function_scoregives you. - Vote trust. Weight votes by account age and reputation before counting them. Cheaper and calmer than fighting abuse after it ranks.
- Moderation levers. Penalty multipliers let you demote garbage without deleting it, which keeps users from discovering invisible rules the hard way.
Watch out
These numbers are 2013-era reverse engineering. HN has changed since, so treat this as the canonical mental model, not a spec.
The exponent is dangerously sensitive. The gap between 1.5 and 2.2 is the difference between a sticky front page and one that refreshes every few minutes. Derive it from your own traffic, not HN's.
Also: pure power-law decay punishes slow-burn content. A great tutorial that takes six hours to catch fire never ranks. Reddit's log-scaled votes handle this more gently — worth a look if your content isn't news.
Try it yourself
def rank(points, hours, gravity=1.8):
return (points - 1) / (hours + 2) ** gravity
# a 100-point story two hours old
baseline = rank(100, 2) # ~8.2
# how many votes to match it at hour 20?
votes = baseline * (20 + 2) ** 1.8 + 1
print(votes) # ~2130 — 21x the votes
# tune gravity for your app:
# 1.3 = sticky feed, 2.2 = minutes-level churnTL;DR
- What changed: The classic 2013 reverse-engineering of HN's ranking is back on the front page — the formula is
(points - 1) / (hours + 2)^1.8plus penalty multipliers. - Why it matters: One exponent controls your entire feed's churn rate, and HN's vote-weighting is the anti-abuse pattern most ranking systems skip.
- Try today: Drop the
rank()function into your next trending endpoint and tune gravity against real traffic.