Skip to content

Instantly share code, notes, and snippets.

@Brajesh2022
Created June 2, 2026 14:47
Show Gist options
  • Select an option

  • Save Brajesh2022/0d6f5246fc3a43c2f69d13b8af025fc2 to your computer and use it in GitHub Desktop.

Select an option

Save Brajesh2022/0d6f5246fc3a43c2f69d13b8af025fc2 to your computer and use it in GitHub Desktop.
Thorough and comprehensive Reddit API documentation and reference manual

REDDIT API COMPREHENSIVE SPECIFICATION & ARCHITECTURAL REFERENCE

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.


TABLE OF CONTENTS

  1. ARCHITECTURAL PHILOSOPHY & TYPING SYSTEM
    • 1.1 The Concept of a "Thing"
    • 1.2 The Concept of a "Listing"
    • 1.3 Fullnames and Prefixes
  2. 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
  3. 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
  4. 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
  5. THE COMMENT TREE RESOLUTION MECHANISM
    • 5.1 JSON Structure of a Post + Comments Page
    • 5.2 Tree Traversal and the replies Listing
    • 5.3 The morechildren Expansion Flow
  6. 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)
  7. 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

1. ARCHITECTURAL PHILOSOPHY & TYPING SYSTEM

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.

1.1 The Concept of a "Thing"

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.

1.2 The Concept of a "Listing"

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.

1.3 Fullnames and Prefixes

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

2. OAUTH2 & SECURITY ARCHITECTURE

Reddit enforces standard OAuth2 authorization. Anonymous requests without a valid user or client token are heavily rate-limited or blocked.

2.1 App Registration Types

To interact with the API, developers register an application in their Reddit preferences. Reddit supports:

  1. Script: Used for command-line scripts or background cron jobs. Authenticates as the app owner.
  2. Web App: Runs on a secure web server. Uses authorization codes. High trust level.
  3. Installed App: Mobile or desktop apps. Low trust level; must use PKCE to protect secrets.

2.2 Client Credentials Flow (Script App)

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:
    grant_type=password&username=BOT_USERNAME&password=BOT_PASSWORD
    
    Or, for read-only non-user credentials:
    grant_type=client_credentials
    
  • Response:
    {
      "access_token": "83427909384-Hsu8a928-uQj",
      "token_type": "bearer",
      "expires_in": 3600,
      "scope": "*"
    }

2.3 Authorization Code Flow with PKCE (Installed App)

For third-party apps where storing a client_secret is unsafe, Proof Key for Code Exchange (PKCE) is required.

  1. Generate Code Verifier & Challenge:

    • Verifier: Cryptographically random string (43–128 characters).
    • Challenge: BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
  2. Redirect User to Authorization Screen:

    • URL: https://www.reddit.com/api/v1/authorize
    • Query Parameters:
      • client_id: App Client ID.
      • response_type: code
      • state: A random CSRF prevention string.
      • redirect_uri: Configured Redirect URL.
      • duration: temporary or permanent
      • scope: Space-separated scopes (e.g. identity read submit vote message).
      • code_challenge: The generated challenge string.
      • code_challenge_method: S256
  3. 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
      

2.4 Headers and User-Agent Guidelines

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)

2.5 Rate Limits & Headers

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.


3. THE CORE DATA MODELS (JSON SCHEMAS)

Below are the complete properties of the primary Reddit objects, with explanations of critical fields.

3.1 Listing Envelope Schema

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": { ... } }
    ]
  }
}

3.2 Link (t3 - Post) Schema

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).

3.3 Comment (t1) Schema

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.

3.4 Subreddit (t5) Schema

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
  }
}

3.5 Account (t2 - User) Schema

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
    }
  }
}

3.6 The "More" Object Schema

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.

4. COMPLETE ENDPOINT REFERENCE

All endpoints assume the base path https://oauth.reddit.com and require standard OAuth Headers.

4.1 Subreddit Endpoints

GET /r/{subreddit}/about

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."
  }
}

GET /subreddits/mine/subscriber

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 t5 objects.

POST /api/subscribe

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:
{}

4.2 Listings & Feeds Endpoints

GET /r/{subreddit}/{sort}

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: (For top and controversial sorts only) hour, day, week, month, year, all.
  • Example Response: A Listing containing t3 objects.

4.3 Comments & Thread Endpoints

GET /r/{subreddit}/comments/{article}

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": { ... } } }
          ]
        }
      }
    ]

POST /api/morechildren

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 the more object.
    • 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!"
          }
        }
      ]
    }
  }
}

4.4 Interaction & Write Endpoints

POST /api/submit

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 for kind=self).
    • url: Target URL (required for kind=link).
    • nsfw: true or false.
  • Example Response:
{
  "json": {
    "errors": [],
    "data": {
      "url": "https://www.reddit.com/r/pics/comments/2a8x1/my_submission/",
      "id": "2a8x1",
      "name": "t3_2a8x1"
    }
  }
}

POST /api/vote

Vote on a post or comment.

  • Body Fields:
    • id: Fullname of target (e.g., t3_2a8x1 or t1_c3v7y7t).
    • dir: 1 (upvote), 0 (clear vote), -1 (downvote).
  • Example Response: {}

POST /api/comment

Reply directly to a post or comment.

  • Body Fields:
    • api_type: "json"
    • thing_id: Fullname of parent (t3_... or t1_...).
    • text: Markdown body.
  • Example Response:
{
  "json": {
    "errors": [],
    "data": {
      "things": [
        {
          "kind": "t1",
          "data": {
            "id": "c9ab2x9",
            "parent_id": "t1_c3v7y7t",
            "body": "Reply created successfully"
          }
        }
      ]
    }
  }
}

4.5 Search Endpoints

GET /r/{subreddit}/search

Search within a specific subreddit, or globally across Reddit using GET /search.

  • Query Parameters:
    • q: Search query string (e.g., "science news").
    • restrict_sr: true or false (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.

4.6 User Account Endpoints

GET /api/v1/me

Retrieve profile details and configuration settings of the current authenticated user.

  • Parameters: None
  • Example Response: A t2 Account schema object.

GET /user/{username}/about

Retrieve public profile information for any user.

  • Path Variables:
    • username: Account name.
  • Example Response: A t2 Account object.

GET /user/{username}/{where}

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 t3 and t1 objects depending on selection.

4.7 Direct Message & Inbox Endpoints

GET /message/inbox

Retrieve messages, replies, and notifications.

  • Query Parameters:
    • filter: "messages", "unread", "sent".
    • limit, after
  • Example Response: A Listing containing t4 (Message) or t1 (Comment notifications) objects.

POST /api/compose

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": []
  }
}

5. THE COMMENT TREE RESOLUTION MECHANISM

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.

5.1 JSON Structure of a Post + Comments Page

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": ""
          }
        }
      ]
    }
  }
]

5.2 Tree Traversal and the replies Listing

In the payload above:

  • A comment that has replies houses a nested Listing object within its replies property.
  • If a comment has no replies, replies is set to the empty string "" or null.
  • 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`);
        }
      });
    }

5.3 The morechildren Expansion Flow

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]
Loading

To stitch newly fetched children from /api/morechildren back into the local tree:

  1. Read the flat things array in the response.
  2. For each t1 thing, check its parent_id.
  3. Find the corresponding parent node in your active DOM/state tree and append the new child comment.
  4. Remove the more placeholder node.

6. ALGORITHMS & CORE RANKING LOGIC

If you are developing a Reddit-like API, replicating its exact feed behaviors requires reproducing two core ranking algorithms.

6.1 Reddit Hot Ranking Algorithm

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).

Mathematical Formula

Let $s$ be the net score: $$s = \text{upvotes} - \text{downvotes}$$

Let $order$ represent the logarithmic scale of interest: $$order = \log_{10}(\max(|s|, 1))$$

Let $sign$ represent the direction of feedback: $$sign = \begin{cases} 1 & \text{if } s > 0 \ -1 & \text{if } s < 0 \ 0 & \text{if } s = 0 \end{cases}$$

Let $seconds$ represent the creation timestamp offset relative to a baseline epoch (December 8, 2005): $$seconds = \text{created_utc} - 1134028003$$

The absolute Hot Score $H$ is computed as: $$H = sign \cdot order + \frac{seconds}{45000}$$

Implications

  • Time Decay: The denominator 45000 corresponds 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.

6.2 Wilson Score Interval for Comments ("Best")

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.

Mathematical Formula

Let $p$ be the observed fraction of positive votes: $$p = \frac{\text{upvotes}}{\text{upvotes} + \text{downvotes}}$$

Let $n$ be the total number of votes: $$n = \text{upvotes} + \text{downvotes}$$

If $n = 0$, the Wilson Score is 0.

Let $z$ be the quantile of the standard normal distribution matching the desired confidence level. For 95% confidence: $$z \approx 1.96$$

The Wilson Score lower bound $W$ is calculated as: $$W = \frac{p + \frac{z^2}{2n} - z \sqrt{\frac{p(1-p)}{n} + \frac{z^2}{4n^2}}}{1 + \frac{z^2}{n}}$$

Implementation (Python)

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) / denominator

6.3 Pagination via Cursor-Based Tokens (before, after)

Reddit 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.

7. SYSTEM DESIGN & DATABASE SCHEMAS FOR A REDDIT-LIKE API

To design a scalable, production-ready system capable of serving millions of reads/writes matching the Reddit API standard, use the following database configurations.

7.1 Relational Database Schema (PostgreSQL)

-- 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);

7.2 Hierarchy Representation (Adjacency List vs. Path Enumeration vs. LTree)

Hierarchical comments can be structured in three ways:

  1. Adjacency List: Each comment has a parent_id foreign 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.
  2. 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).
  3. PostgreSQL LTree extension (Recommended):
    • Uses optimized indexing for path labels.
    • Querying all children of comment c100001 is simple and indexed:
      SELECT * FROM comments WHERE path <@ 'c100001';

7.3 Caching and Read-Side Optimization

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 SELECT queries. Compute and save the rating score immediately when a vote is recorded.
  • Denormalize Counts: Store num_comments and subscribers_count directly on the parent row and increment/decrement them via transaction triggers, rather than running expensive aggregate COUNT(*) queries on active tables.
  • Redis Caching:
    • Post Lists: Cache the serialized JSON of subreddit feeds in Redis sorted sets (ZSET), with the score of the set representing the post's hot_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.

End of Specification. Use this system design blueprint to build scalable, high-performance web APIs styled after the Reddit design standard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment