Lemmy — Project Specification

Source: ~/code/rust/rust/lemmy/ (https://github.com/LemmyNet/lemmy) Language: Rust (edition 2024, pinned to toolchain 1.95) License: AGPL-3.0 Version: 1.0.0-beta.1 Description: A link aggregator for the fediverse


Architecture

[Browser/App] <--REST/JSON--> [lemmy_server (actix-web)]
                                    |
                         +----------+----------+
                         |                     |
                    [PostgreSQL]        [pictrs (images)]
                         |
                    [ActivityPub] <--> [Other Fediverse Instances]
                         |
                    [SMTP Email]

The codebase is a Rust workspace of 39 crates under crates/. The key layers:

Layer Crate(s) Purpose
Server lemmy_server Binary entrypoint, actix-web HttpServer, middleware stack
API (current) lemmy_api_routes Route definitions for API v4
API (legacy) lemmy_api_routes_v3 Route definitions for API v3 (deprecated)
API Handlers lemmy_api, lemmy_api_crud Core handler logic + CRUD operations
API Types lemmy_api_common Shared request/response types
API Utils lemmy_api_utils JWT auth, authorization checks, rate limiting, Extism WASM plugins, notification dispatch
DB Schema lemmy_db_schema, lemmy_db_schema_file Diesel ORM models, source definitions, newtypes, auto-generated schema.rs
DB Views lemmy_db_views_* (24 crates) Read-model queries (joins, filtering, sorting, pagination, visibility rules)
ActivityPub lemmy_apub, lemmy_apub_activities, lemmy_apub_objects, lemmy_apub_send Federation layer — sending/receiving ActivityPub activities
Routes lemmy_routes Non-API HTTP routes: RSS/Atom feeds, image proxy, nodeinfo, webfinger, Prometheus metrics
Email lemmy_email SMTP email sending with i18n templates
Utils lemmy_utils Error types, rate limiting, settings/config (HJSON), caching
Diesel Utils lemmy_diesel_utils DB connection pool, migrations, pagination utilities

API Surface (v4, all under /api/v4/)

Site

Method Path Description
GET /site Get site info (combined response with site, admins, user state)
POST /site Create site (initial setup)
PUT /site Edit site configuration
POST /site/icon Upload site icon
DELETE /site/icon Delete site icon
POST /site/banner Upload site banner
DELETE /site/banner Delete site banner

Community

Method Path Description
GET /community Get community by ID or name
POST /community Create community
PUT /community Edit community
DELETE /community Delete community
GET /community/list List communities (paginated, filtered)
GET /community/random Get random community
POST /community/follow Follow/unfollow community
POST /community/remove Mod: remove community
POST /community/transfer Transfer community ownership
POST /community/ban_user Mod: ban user from community
POST /community/mod Mod: add/remove moderator
POST /community/icon Upload community icon
DELETE /community/icon Delete community icon
POST /community/banner Upload community banner
DELETE /community/banner Delete community banner
POST /community/tag Create community tag
PUT /community/tag Edit community tag
DELETE /community/tag Delete community tag
PUT /community/notifications Edit community notification settings
GET /community/pending_follows/list List pending follow requests
POST /community/pending_follows/approve Approve/deny pending follow
POST /community/report Report a community
PUT /community/report/resolve Resolve community report

Post

Method Path Description
GET /post Get post by ID
POST /post Create post
PUT /post Edit post
DELETE /post Delete post
GET /post/list List posts (paginated, with filters/sorts)
POST /post/remove Mod: remove post
POST /post/mark_as_read Mark single post as read
POST /post/mark_as_read/many Mark multiple posts as read
POST /post/hide Hide post from listings
POST /post/lock Lock post (prevent new comments)
POST /post/feature Feature/sticky post in community or instance
POST /post/like Vote on post (score: -1, 0, 1)
GET /post/like/list List users who voted on post
PUT /post/save Save/bookmark post
POST /post/report Report a post
PUT /post/report/resolve Resolve post report
PUT /post/notifications Edit post notification settings
PUT /post/mod_edit Mod: edit post body
POST /post/warn Issue warning on a post
GET /post/site_metadata Fetch URL metadata (OpenGraph)

Comment

Method Path Description
GET /comment Get comment by ID
POST /comment Create comment (with optional parent_id for threading)
PUT /comment Edit comment
DELETE /comment Delete comment
GET /comment/list List comments on a post (with depth, sort, max_depth, parent_id)
GET /comment/list/slim Slim comment list (IDs only for unread counts)
POST /comment/remove Mod: remove comment
POST /comment/distinguish Mod: distinguish comment
POST /comment/like Vote on comment
GET /comment/like/list List users who voted on comment
PUT /comment/save Save/bookmark comment
POST /comment/lock Lock comment thread
POST /comment/warn Issue warning on a comment
POST /comment/report Report a comment
PUT /comment/report/resolve Resolve comment report

Private Messages

Method Path Description
POST /private_message Create private message
PUT /private_message Edit private message
DELETE /private_message Delete private message
POST /private_message/report Report a private message
PUT /private_message/report/resolve Resolve private message report

Reports

Method Path Description
GET /report/list List all reports (combined, paginated)

User / Account

Method Path Description
POST /account/auth/register Register new user
POST /account/auth/login Login (returns JWT)
POST /account/auth/logout Logout
POST /account/auth/password_reset Request password reset email
POST /account/auth/password_change Change password with reset token
PUT /account/auth/change_password Change password (authenticated)
POST /account/auth/totp/generate Generate TOTP 2FA secret
POST /account/auth/totp/edit Update TOTP configuration
POST /account/auth/verify_email Verify email with token
POST /account/auth/resend_verification_email Resend verification email
GET /account Get my user (authenticated user with settings, follows, mods, blocks)
GET /account/auth/get_captcha Get CAPTCHA
GET /account/unread_counts Get unread counts (replies, mentions, PMs)
GET /account/notification/list List notifications
POST /account/notification/mark_as_read/all Mark all notifications read
POST /account/notification/mark_as_read Mark single notification read
DELETE /account Delete account
GET /account/login/list List active login sessions
GET /account/validate_auth Validate JWT is still valid
POST /account/donation_dialog_shown Mark donation dialog shown
POST /account/avatar Upload avatar
DELETE /account/avatar Delete avatar
POST /account/banner Upload banner
DELETE /account/banner Delete banner
POST /account/block/person Block/unblock a person
POST /account/block/community Block/unblock a community
POST /account/block/instance/communities Block all communities on an instance
POST /account/block/instance/persons Block all persons on an instance
GET /account/saved List saved posts/comments
GET /account/read List read posts
GET /account/hidden List hidden posts
GET /account/liked List liked posts
PUT /account/settings/save Save user settings
GET /account/settings/export Export user settings
POST /account/settings/import Import user settings
GET /account/data/export Export all user data
POST /account/invite Create invitation
DELETE /account/invite Revoke invitation
GET /account/invite/list List invitations
DELETE /account/media Delete an image
GET /account/media/list List user media

Person (Public Profiles)

Method Path Description
GET /person Get person by ID
GET /person/list List persons
GET /person/content List person’s content (posts + comments, combined, paginated)
POST /person/note Add a moderator note to a person

Admin

Method Path Description
POST /admin/add Add/remove admin
GET /admin/registration_application Get single registration application
GET /admin/registration_application/list List registration applications
PUT /admin/registration_application/approve Approve/reject registration application
POST /admin/purge/person Purge a person and all their content
POST /admin/purge/community Purge a community
POST /admin/purge/post Purge a post
POST /admin/purge/comment Purge a comment
POST /admin/tagline Create site tagline
PUT /admin/tagline Edit tagline
DELETE /admin/tagline Delete tagline
GET /admin/tagline/list List taglines
POST /admin/ban Ban/unban person from site
GET /admin/users List all users (admin)
POST /admin/instance/block Block an instance
POST /admin/instance/allow Allow an instance

Other

Method Path Description
GET /modlog Get moderator log
GET /search Search (posts, comments, communities, users, URL)
GET /resolve_object Resolve a federated object by ID
GET /federated_instances List federated instances
POST /custom_emoji Create custom emoji
PUT /custom_emoji Edit custom emoji
DELETE /custom_emoji Delete custom emoji
GET /custom_emoji/list List custom emojis
POST /oauth_provider Create OAuth provider
PUT /oauth_provider Edit OAuth provider
DELETE /oauth_provider Delete OAuth provider
POST /oauth/authenticate Authenticate with OAuth
POST /image Upload image (to pictrs)
DELETE /image Delete image (admin)
GET /image/proxy Image proxy (privacy-preserving)
GET /image/health pictrs health check
GET /image/list List all media (admin)
GET /image/{filename} Get/redirect to image

Non-API Routes

Path Description
/nodeinfo/2.1 NodeInfo protocol (federation metadata)
/.well-known/webfinger WebFinger (account discovery)
/.well-known/nodeinfo NodeInfo well-known link
/feeds/{type}.xml RSS/Atom feeds (community, user, front page)
/metrics Prometheus metrics

Key Data Models

Post

Fields: id, name, url, body, creator_id, community_id, removed, deleted, locked, featured_community, featured_local, nsfw, embed_title, embed_description, embed_html, thumbnail_url, ap_id, local, language_id, created, updated, published

Comment

Fields: id, creator_id, post_id, parent_id (self-referencing for threading), content, removed, deleted, distinguished, language_id, ap_id, local, path (materialized path Ltree for tree queries), published, updated

Community

Fields: id, name, title, description, removed, deleted, nsfw, actor_id, local, icon, banner, posting_restricted_to_mods, instance_id, published, updated

Person / User

Fields: id, name, display_name, avatar, banner, bio, banned, deleted, actor_id, local, bot_account, matrix_user_id, admin, published, updated

Site

Fields: id, name, sidebar, icon, banner, description, actor_id, last_refreshed_at, inbox_url, public_key, instance_id, published, updated


Key Differences from Threadlight

Feature Lemmy Threadlight
Language Rust (actix-web + Diesel ORM) Go (Gin + pgx)
Federation ActivityPub (full fediverse) None (single-instance)
Comments Full threaded (parent_id + ltree path, depth queries) Via Interaction metadata (flat, no threading)
Voting Dedicated like endpoints returning updated views Via Interaction model
Media pictrs external image server None (no upload endpoint)
Site info Rich combined GetSiteResponse No site endpoint (stubbed)
DB schema 340+ Diesel migrations Simple migrations
Rate limiting Per-endpoint tunable limits Global rate limit
WASM plugins Extism-based custom plugins None
OAuth Provider authentication None
2FA TOTP support None
CAPTCHA Built-in captcha None
Custom emoji Full support None
Taglines Site taglines None
Private messages Full PM system None
Multi-community Group communities None
Modlog Full mod action log None
Registration queue Application/approval workflow None
Email verification Required for registration Present but minimal
Invite system User invitation codes Present via invite_code
User settings export/import Full settings backup None

Architecture Strengths (Why Lemmy Is Mature)

  1. Workspace separation: 39 focused crates instead of one monolithic internal/ — clean dependency graph, faster compilation of unchanged crates
  2. View layer pattern: DB_views crates encapsulate all read-model complexity (joins, filtering, visibility rules, pagination) — handlers just call view.query()
  3. ActivityPub federation: Full spec implementation with type-safe activity serialization
  4. Derived aggregates: Post aggregates (score, upvotes, downvotes, comment count) stored in separate tables with trigger-based updates — no counting on read
  5. Materialized path for comments: PostgreSQL Ltree enables efficient subtree queries and depth-limited fetches
  6. Rate limiting: Per-endpoint configurable rate limits, not a single global limiter
  7. Extensive migration history: 340+ migrations document every schema change since 2019