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