This document provides an exhaustive, production-grade specification of the Reddit API. It covers the architectural philosophy, data models, authentication flows, core endpoints with complete JSON payloads, advanced comment tree mechanics, ranking algorithms, and recommendations for designing your own Reddit-like API from scratch.
- ARCHITECTURAL PHILOSOPHY & TYPING SYSTEM
- 1.1 The Concept of a "Thing"
- 1.2 The Concept of a "Listing"
- 1.3 Fullnames and Prefixes
- OAUTH2 & SECURITY ARCHITECTURE
- 2.1 App Registration Types
- 2.2 Client Credentials Flow (Script App)
- 2.3 Authorization Code Flow with PKCE (Installed App)
- 2.4 Headers and User-Agent Guidelines
- 2.5 Rate Limits & Headers
- THE CORE DATA MODELS (JSON SCHEMAS)
- 3.1 Listing Envelope Schema
- 3.2 Link (t3 - Post) Schema
- 3.3 Comment (t1) Schema
- 3.4 Subreddit (t5) Schema
- 3.5 Account (t2 - User) Schema
- 3.6 The "More" Object Schema
- COMPLETE ENDPOINT REFERENCE
- 4.1 Subreddit Endpoints
- 4.2 Listings & Feeds Endpoints
- 4.3 Comments & Thread Endpoints
- 4.4 Interaction & Write Endpoints
- 4.5 Search Endpoints
- 4.6 User Account Endpoints
- 4.7 Direct Message & Inbox Endpoints
- THE COMMENT TREE RESOLUTION MECHANISM
- 5.1 JSON Structure of a Post + Comments Page
- 5.2 Tree Traversal and the
repliesListing - 5.3 The
morechildrenExpansion Flow
- ALGORITHMS & CORE RANKING LOGIC
- 6.1 Reddit Hot Ranking Algorithm
- 6.2 Wilson Score Interval for Comments ("Best")
- 6.3 Pagination via Cursor-Based Tokens (
before,after)
- SYSTEM DESIGN & DATABASE SCHEMAS FOR A REDDIT-LIKE API
- 7.1 Relational Database Schema (PostgreSQL)
- 7.2 Hierarchy Representation (Adjacency List vs. Path Enumeration vs. LTree)
- 7.3 Caching and Read-Side Optimization
The Reddit API is designed around a highly structured, object-oriented data model where every resource is subclassed from a base interface called a Thing. Resources are grouped and paginated using an envelope object called a Listing.
In Reddit's architecture, a "Thing" is any object that has a unique identifier and represents a piece of content, a user, or a container. Every Thing shares two common base fields:
kind: A string indicating the object type.data: An object containing the actual properties of the resource.
A "Listing" is a paginated collection of Things. It acts as an envelope. It contains a list of children, along with cursors for forward and backward pagination. Every Listing shares the following envelope:
kind: Always"Listing".data: An object containing:before: A fullname token pointing to the item before this batch (null if first page).after: A fullname token pointing to the item after this batch (null if last page).dist: The number of children in this listing.modhash: An anti-CSRF token (primarily used in older non-OAuth contexts, empty or ignored in modern OAuth requests).children: An array of Things.
Instead of passing raw numerical or UUID database keys, the Reddit API exposes Fullnames. A fullname is a unique identifier consisting of a prefix (which denotes the Thing type) followed by an underscore (_) and a Base36-encoded identifier.
| Prefix | Type | Description | Example |
|---|---|---|---|
t1 |
Comment | A reply to a post or another comment. | t1_c3v7y7t |
t2 |
Account | A registered user account. | t2_83x9y |
t3 |
Link | A post (link, text, image, video). | t3_12x98y |
t4 |
Message | A private direct message. | t4_m3v821 |
t5 |
Subreddit | A community. | t5_2qh1i (r/askreddit) |
t6 |
Award | An award given to a post or comment. | t6_a2x98j |
t8 |
Subreddit Relation | Relationship between a user and a subreddit. | t8_r3x98a |
Reddit enforces standard OAuth2 authorization. Anonymous requests without a valid user or client token are heavily rate-limited or blocked.
To interact with the API, developers register an application in their Reddit preferences. Reddit supports:
- Script: Used for command-line scripts or background cron jobs. Authenticates as the app owner.
- Web App: Runs on a secure web server. Uses authorization codes. High trust level.
- Installed App: Mobile or desktop apps. Low trust level; must use PKCE to protect secrets.
For internal tasks or non-interactive bots, the Script flow provides quick access.
- Endpoint:
POST https://www.reddit.com/api/v1/access_token - Headers:
Authorization:Basic <BASE64_ENCODED(client_id:client_secret)>Content-Type:application/x-www-form-urlencoded
- Body:
Or, for read-only non-user credentials:grant_type=password&username=BOT_USERNAME&password=BOT_PASSWORDgrant_type=client_credentials - Response:
{ "access_token": "83427909384-Hsu8a928-uQj", "token_type": "bearer", "expires_in": 3600, "scope": "*" }
For third-party apps where storing a client_secret is unsafe, Proof Key for Code Exchange (PKCE) is required.
-
Generate Code Verifier & Challenge:
- Verifier: Cryptographically random string (43–128 characters).
- Challenge:
BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
-
Redirect User to Authorization Screen:
- URL:
https://www.reddit.com/api/v1/authorize - Query Parameters:
client_id: App Client ID.response_type:codestate: A random CSRF prevention string.redirect_uri: Configured Redirect URL.duration:temporaryorpermanentscope: Space-separated scopes (e.g.identity read submit vote message).code_challenge: The generated challenge string.code_challenge_method:S256
- URL:
-
Exchange Authorization Code for Token:
- Endpoint:
POST https://www.reddit.com/api/v1/access_token - Headers:
Authorization:Basic <BASE64_ENCODED(client_id:)>(no secret is passed, keep client_secret empty)Content-Type:application/x-www-form-urlencoded
- Body:
grant_type=authorization_code&code=AUTH_CODE_FROM_REDIRECT&redirect_uri=REDIRECT_URI&code_verifier=ORIGINAL_CODE_VERIFIER
- Endpoint:
Reddit requires a strict, descriptive User-Agent string. Generic headers (e.g., python:requests, Mozilla/5.0) trigger immediate 429 Too Many Requests errors.
- Format:
<platform>:<app ID>:<version string> (by /u/<reddit username>) - Example:
android:com.example.myredditapp:v1.2.0 (by /u/developer_username)
All authenticated API requests must use the base URL https://oauth.reddit.com (instead of www.reddit.com) and contain:
Authorization: Bearer <ACCESS_TOKEN>
User-Agent: android:com.example.myredditapp:v1.2.0 (by /u/developer_username)Reddit tracks rate limits dynamically. Every response contains headers indicating current allocation:
x-ratelimit-remaining: Number of requests remaining in the current window.x-ratelimit-used: Number of requests used in the current window.x-ratelimit-reset: Seconds remaining until the window resets.
Important
Rate limits are typically evaluated on a sliding 10-minute window (usually allowing up to 600 requests per 10 minutes per client/user token). Exceeding this triggers a 429 Too Many Requests status code with a JSON body indicating when to retry.
Below are the complete properties of the primary Reddit objects, with explanations of critical fields.
Every response returning a list of comments, posts, search results, or inbox items uses this structure.
{
"kind": "Listing",
"data": {
"after": "t3_16yabc1",
"before": null,
"dist": 2,
"modhash": null,
"children": [
{ "kind": "t3", "data": { ... } },
{ "kind": "t3", "data": { ... } }
]
}
}Represents a text post (self-post), image, video, link, or gallery.
| Field | Type | Description |
|---|---|---|
id |
string | Base36 ID of the post (e.g., "16yabc1"). |
name |
string | Fullname (e.g., "t3_16yabc1"). |
title |
string | The title of the post. |
subreddit |
string | Name of the subreddit (e.g., "AskReddit"). |
subreddit_id |
string | Fullname of the subreddit ("t5_2qh1i"). |
author |
string | Username of the creator (e.g., "spez"). |
author_fullname |
string | Fullname of the author (e.g., "t2_83x9y"). |
selftext |
string | Markdown body of a self-post. Empty for links/media. |
selftext_html |
string | Sanitized HTML version of the markdown selftext. |
score |
integer | Total net votes: ups - downs. |
ups |
integer | Total upvotes (under modern API, identical to score). |
downs |
integer | Total downvotes (always 0 in the modern API to obscure exact votes). |
upvote_ratio |
float | Percentage of votes that are upvotes (between 0.0 and 1.0). |
likes |
boolean | true if upvoted by the caller, false if downvoted, null if unvoted. |
num_comments |
integer | Total number of comments in the thread (recursive). |
permalink |
string | Relative URL path (e.g., /r/AskReddit/comments/16yabc1/sample/). |
url |
string | Direct target URL (identical to permalink for self-posts). |
is_self |
boolean | true if the post is a markdown text-only self-post. |
is_video |
boolean | true if the post hosts a Reddit Native Video. |
over_18 |
boolean | true if marked as NSFW (Not Safe For Work). |
spoiler |
boolean | true if marked as a spoiler. |
stickied |
boolean | true if pinned to the top of the subreddit feed. |
created_utc |
float | Epoch timestamp of creation (e.g., 1685714788.0). |
Represents a comment replying to a post or a parent comment.
| Field | Type | Description |
|---|---|---|
id |
string | Base36 ID of the comment (e.g., "c3v7y7t"). |
name |
string | Fullname (e.g., "t1_c3v7y7t"). |
parent_id |
string | Fullname of the parent (t3_... if a post, t1_... if a comment). |
link_id |
string | Fullname of the root post (t3_...). |
author |
string | Username of the comment author. |
author_fullname |
string | Fullname of the comment author. |
body |
string | Markdown body text of the comment. |
body_html |
string | Sanitized HTML representation of the body. |
score |
integer | Total net votes. |
likes |
boolean | true (upvoted), false (downvoted), null (unvoted). |
replies |
object | A Listing envelope containing replies, or an empty string "" if none. |
depth |
integer | Zero-indexed nesting depth. |
distinguished |
string | "moderator", "admin", or null. |
created_utc |
float | Epoch timestamp of creation. |
Represents a community.
{
"kind": "t5",
"data": {
"id": "2qh1i",
"name": "t5_2qh1i",
"display_name": "AskReddit",
"title": "r/AskReddit - What's on your mind?",
"header_img": "https://a.thumbs.redditmedia.com/header.png",
"active_user_count": 48102,
"subscribers": 42938102,
"description": "r/AskReddit is the place to ask and answer thought-provoking questions.",
"description_html": "<!-- sanitized HTML description -->",
"public_description": "Ask reddit...",
"over18": false,
"subreddit_type": "public",
"created_utc": 1201210455.0,
"user_is_subscriber": true,
"user_is_moderator": false
}
}Represents a user account.
{
"kind": "t2",
"data": {
"id": "83x9y",
"name": "t2_83x9y",
"created_utc": 1134028003.0,
"link_karma": 12890,
"comment_karma": 89402,
"total_karma": 102292,
"is_gold": true,
"is_mod": true,
"has_verified_email": true,
"subreddit": {
"icon_img": "https://www.redditstatic.com/avatars/avatar.png",
"public_description": "Official account of spez",
"subscribers": 128912
}
}
}When a comment tree is too deep or exceeds the maximum child limit per node, instead of comments, the children array of a replies Listing contains a more object.
{
"kind": "more",
"data": {
"count": 47,
"name": "t1_c3v89da",
"id": "c3v89da",
"parent_id": "t1_c3v7y7t",
"children": [
"c3v8a21",
"c3v8b42",
"c3v8c99"
]
}
}count: The total count of hidden comments represented by this node.children: A list of Base36 comment IDs that can be retrieved using/api/morechildren.
All endpoints assume the base path https://oauth.reddit.com and require standard OAuth Headers.
Retrieve settings, visual properties, and membership statistics of a specific community.
- Parameters: None
- Example Response:
{
"kind": "t5",
"data": {
"display_name": "pics",
"subscribers": 31405901,
"public_description": "A place for pictures and photographs."
}
}Retrieve subreddits the authenticated user is subscribed to.
- Query Parameters:
limit: Number of items to return (max 100).after: Pagination token.
- Example Response: A Listing containing
t5objects.
Join or leave a subreddit.
- Content-Type:
application/x-www-form-urlencoded - Body Fields:
action:"sub"to subscribe,"unsub"to unsubscribe.sr: Fullname of the subreddit (e.g.t5_2qh1i).skip_initial_defaults:true(optional).
- Example Response:
{}Retrieve post feeds for a subreddit. Use r/all for global feed or omit r/{subreddit} to request the homepage.
- Path Variables:
sort:hot,new,rising,controversial,top
- Query Parameters:
limit: Max number of items (default 25, max 100).after: Cursoring token (fullname of the last item in previous batch).before: Cursoring token (fullname of the first item in current batch).t: (Fortopandcontroversialsorts only)hour,day,week,month,year,all.
- Example Response: A Listing containing
t3objects.
Retrieve a post along with its entire comment tree.
- Path Variables:
article: Base36 post ID (e.g.,16yabc1).
- Query Parameters:
comment: (Optional) ID of a specific comment to treat as root (single-thread view).context: (Optional) Number of parent comments to show when deep-linking.depth: (Optional) Maximum depth limit for the comment tree.limit: (Optional) Maximum number of root comments to return.sort:confidence(Best),top,new,hot,controversial,old.
- Example Response:
An array of exactly two Listing elements:
[ { "kind": "Listing", "data": { "children": [ { "kind": "t3", "data": { "id": "16yabc1", "title": "Example Post" } } ] } }, { "kind": "Listing", "data": { "children": [ { "kind": "t1", "data": { "body": "Root comment...", "replies": { ... } } } ] } } ]
Expand a more placeholder comment node.
- Content-Type:
application/x-www-form-urlencoded - Body Fields:
api_type: Must be"json".link_id: Fullname of the parent Link (t3_16yabc1).children: Comma-separated list of Base36 IDs listed in themoreobject.sort: Sort method matching original query (confidence,top, etc.).
- Example Response:
Returns a JSON structure listing the newly fetched comments in a flat array, mapping their hierarchies via
parent_id.
{
"json": {
"errors": [],
"data": {
"things": [
{
"kind": "t1",
"data": {
"id": "c3v8a21",
"parent_id": "t1_c3v7y7t",
"body": "First dynamic child!"
}
}
]
}
}
}Submit a new post to a subreddit.
- Content-Type:
application/x-www-form-urlencoded - Body Fields:
api_type:"json"sr: Name of the subreddit (e.g."pics").kind:"self"(text),"link","image","video".title: The title string.text: Markdown body (required forkind=self).url: Target URL (required forkind=link).nsfw:trueorfalse.
- Example Response:
{
"json": {
"errors": [],
"data": {
"url": "https://www.reddit.com/r/pics/comments/2a8x1/my_submission/",
"id": "2a8x1",
"name": "t3_2a8x1"
}
}
}Vote on a post or comment.
- Body Fields:
id: Fullname of target (e.g.,t3_2a8x1ort1_c3v7y7t).dir:1(upvote),0(clear vote),-1(downvote).
- Example Response:
{}
Reply directly to a post or comment.
- Body Fields:
api_type:"json"thing_id: Fullname of parent (t3_...ort1_...).text: Markdown body.
- Example Response:
{
"json": {
"errors": [],
"data": {
"things": [
{
"kind": "t1",
"data": {
"id": "c9ab2x9",
"parent_id": "t1_c3v7y7t",
"body": "Reply created successfully"
}
}
]
}
}
}Search within a specific subreddit, or globally across Reddit using GET /search.
- Query Parameters:
q: Search query string (e.g.,"science news").restrict_sr:trueorfalse(limit results to target subreddit).sort:relevance,hot,top,new,comments.t: Time range:hour,day,week,month,year,all.limit&after/before: Pagination variables.
- Example Response: A Listing containing matching
t3(Link) objects.
Retrieve profile details and configuration settings of the current authenticated user.
- Parameters: None
- Example Response: A
t2Account schema object.
Retrieve public profile information for any user.
- Path Variables:
username: Account name.
- Example Response: A
t2Account object.
Retrieve history logs of user actions.
- Path Variables:
where:overview,submitted,comments,upvoted,downvoted,saved.
- Query Parameters:
limit,after,before
- Example Response: A Listing of
t3andt1objects depending on selection.
Retrieve messages, replies, and notifications.
- Query Parameters:
filter:"messages","unread","sent".limit,after
- Example Response: A Listing containing
t4(Message) ort1(Comment notifications) objects.
Send a private direct message to another user.
- Body Fields:
api_type:"json"to: Username of recipient.subject: Subject string.text: Markdown body.
- Example Response:
{
"json": {
"errors": []
}
}The representation of nested conversation trees in JSON is one of the most distinctive aspects of Reddit's API. A thread can scale to tens of thousands of nested replies. Sending this raw structure recursively requires robust data modelling.
When requesting a thread, Reddit responds with a list containing exactly two elements: the Post envelope and the Comments tree.
[
{
"kind": "Listing",
"data": {
"children": [
{
"kind": "t3",
"data": {
"id": "16yabc1",
"title": "Welcome to my discussion!"
}
}
]
}
},
{
"kind": "Listing",
"data": {
"children": [
{
"kind": "t1",
"data": {
"id": "c100001",
"body": "This is a top-level comment.",
"replies": {
"kind": "Listing",
"data": {
"children": [
{
"kind": "t1",
"data": {
"id": "c100002",
"parent_id": "t1_c100001",
"body": "This is a nested reply.",
"replies": ""
}
}
]
}
}
}
},
{
"kind": "t1",
"data": {
"id": "c100003",
"body": "Another top-level comment.",
"replies": ""
}
}
]
}
}
]In the payload above:
- A comment that has replies houses a nested
Listingobject within itsrepliesproperty. - If a comment has no replies,
repliesis set to the empty string""ornull. - Clients traverse this payload using recursive depth-first rendering:
function renderComments(commentListing) { if (!commentListing || commentListing === "") return; commentListing.data.children.forEach(child => { if (child.kind === "t1") { console.log(`Body: ${child.data.body}`); // Recursively traverse replies renderComments(child.data.replies); } else if (child.kind === "more") { console.log(`Placeholder to load ${child.data.count} more replies`); } }); }
If a deep subtree isn't returned initially, the client encounters a more object.
graph TD
A[Render Comment Tree] --> B{Node type?}
B -- t1 --> C[Render Comment Markdown]
C --> D[Recurse into replies]
B -- more --> E[Render 'Load More Comments' Button]
E -- User Clicks --> F[Call POST /api/morechildren]
F --> G[Receive flat list of t1 elements]
G --> H[Stitch new t1s into correct parent_id nodes]
To stitch newly fetched children from /api/morechildren back into the local tree:
- Read the flat
thingsarray in the response. - For each
t1thing, check itsparent_id. - Find the corresponding parent node in your active DOM/state tree and append the new child comment.
- Remove the
moreplaceholder node.
If you are developing a Reddit-like API, replicating its exact feed behaviors requires reproducing two core ranking algorithms.
Used for calculating the hot feeds of subreddits and the homepage. It balances user feedback (net score) with time decay (newer items rank exponentially higher than older items).
Let
Let
Let
Let
The absolute Hot Score
-
Time Decay: The denominator
45000corresponds to$12.5$ hours. A post created$12.5$ hours after an older post needs$10$ times as many net upvotes (due to the$\log_{10}$ scale) to achieve an equal ranking score. - Diminishing Returns: The logarithmic scale ensures that the difference between 10 and 100 upvotes has the same ranking impact as the difference between 100 and 1,000 upvotes.
Standard "Top" sorting (sorting by simple upvotes - downvotes or ratio upvotes / total_votes) has two key weaknesses:
- An item with 1 upvote and 0 downvotes (100% positive) ranks higher than an item with 99 upvotes and 1 downvote (99% positive).
- High-traffic items with massive feedback completely overshadow newer items.
Reddit's "Best" comment sort resolves this using the Wilson Score Interval to calculate the lower bound of the 95% confidence interval for the probability of a positive vote.
Let
Let
If
Let
The Wilson Score lower bound
import math
def wilson_score(ups: int, downs: int) -> float:
n = ups + downs
if n == 0:
return 0.0
z = 1.96 # 95% confidence
p = float(ups) / n
left = p + (z * z) / (2 * n)
right = z * math.sqrt((p * (1 - p) + (z * z) / (4 * n)) / n)
denominator = 1 + (z * z) / n
return (left - right) / denominatorReddit does not use database offset-based pagination (OFFSET 100 LIMIT 25) because offsets are highly unstable on dynamic lists. If five new posts are submitted while a user is reading page 1, loading page 2 with offsets will duplicate five posts.
Instead, Reddit uses Cursor Pagination based on Fullnames:
limit: Number of items requested.after: The fullname of the last item currently rendered (e.g.t3_16yabc1). The query will fetch resources created prior to that fullname.before: The fullname of the first item currently rendered. The query will fetch resources created after that fullname.
To design a scalable, production-ready system capable of serving millions of reads/writes matching the Reddit API standard, use the following database configurations.
-- Accounts (t2)
CREATE TABLE accounts (
id VARCHAR(15) PRIMARY KEY, -- Base36 ID, e.g. '83x9y'
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE,
password_hash VARCHAR(255) NOT NULL,
link_karma INT DEFAULT 0,
comment_karma INT DEFAULT 0,
created_utc TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Subreddits (t5)
CREATE TABLE subreddits (
id VARCHAR(15) PRIMARY KEY, -- Base36 ID, e.g. '2qh1i'
display_name VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(100) NOT NULL,
public_description TEXT,
subscribers_count INT DEFAULT 0,
created_utc TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Links / Posts (t3)
CREATE TABLE links (
id VARCHAR(15) PRIMARY KEY, -- Base36 ID, e.g. '16yabc1'
subreddit_id VARCHAR(15) NOT NULL REFERENCES subreddits(id) ON DELETE CASCADE,
author_id VARCHAR(15) NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
title VARCHAR(300) NOT NULL,
selftext TEXT,
is_self BOOLEAN DEFAULT TRUE,
url TEXT,
upvotes INT DEFAULT 1,
downvotes INT DEFAULT 0,
score INT DEFAULT 1,
hot_score DOUBLE PRECISION DEFAULT 0.0,
num_comments INT DEFAULT 0,
created_utc TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Comments (t1)
CREATE TABLE comments (
id VARCHAR(15) PRIMARY KEY, -- Base36 ID
link_id VARCHAR(15) NOT NULL REFERENCES links(id) ON DELETE CASCADE,
parent_fullname VARCHAR(20) NOT NULL, -- fullname, e.g. 't3_16yabc1' or 't1_c100001'
author_id VARCHAR(15) NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
body TEXT NOT NULL,
upvotes INT DEFAULT 1,
downvotes INT DEFAULT 0,
score INT DEFAULT 1,
wilson_score DOUBLE PRECISION DEFAULT 0.0,
path LTREE, -- Used for PostgreSQL LTree hierarchy optimization
created_utc TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Indices for Feed Pagination & Sorting
CREATE INDEX idx_links_subreddit_hot ON links (subreddit_id, hot_score DESC, created_utc DESC);
CREATE INDEX idx_links_global_hot ON links (hot_score DESC, created_utc DESC);
CREATE INDEX idx_comments_link_path ON comments (link_id, path);Hierarchical comments can be structured in three ways:
- Adjacency List: Each comment has a
parent_idforeign key.- Pros: Extremely simple writes.
- Cons: Fetching a full nested tree requires complex recursive Common Table Expressions (CTEs) in SQL, which slow down severely at high scale.
- Path Enumeration: Store the complete path from root to node as a string (e.g.,
'c100001.c100005.c100009').- Pros: Easy subtree retrieval using string prefixes.
- Cons: Heavy indexing required; updating paths when nodes move is slow (though comments rarely move parent nodes).
- PostgreSQL LTree extension (Recommended):
- Uses optimized indexing for path labels.
- Querying all children of comment
c100001is simple and indexed:SELECT * FROM comments WHERE path <@ 'c100001';
Reddit is heavily read-biased. Posts are read millions of times more often than they are written. To support this:
- Compute Scores on Write: Do not calculate hot score or Wilson interval dynamically during
SELECTqueries. Compute and save the rating score immediately when a vote is recorded. - Denormalize Counts: Store
num_commentsandsubscribers_countdirectly on the parent row and increment/decrement them via transaction triggers, rather than running expensive aggregateCOUNT(*)queries on active tables. - Redis Caching:
- Post Lists: Cache the serialized JSON of subreddit feeds in Redis sorted sets (
ZSET), with thescoreof the set representing the post'shot_score. This makes feed pages lightning-fast reads. - Comment Subtrees: Cache comment subtrees as individual JSON fragments. As new comments arrive, invalidate only the parent's cached fragment.
- Post Lists: Cache the serialized JSON of subreddit feeds in Redis sorted sets (
End of Specification. Use this system design blueprint to build scalable, high-performance web APIs styled after the Reddit design standard.