Lemmy
Audited from github.com/LemmyNet/lemmy
Lemmy is a decentralised, federated link aggregator and forum similar to Reddit, with a Rust backend on Actix Web, PostgreSQL through Diesel, and ActivityPub federation between independently run instances.
- Language
- Rust
- Database
- PostgreSQL
- Hosting
- Docker
- License
- AGPL-3.0
- Running for
- 7 years
- Team
- 20+ people
Why this architecture
Lemmy splits its Rust backend into many small crates (per database view, API, ActivityPub, email) over one PostgreSQL schema with heavy migrations, so federation, the local API and queries evolve separately while a single binary serves an instance.
Tech stack by layer
11 technologies · audited Oct 2, 2026- RustBackend language for the lemmy_server binary and all workspace crates (edition 2024, Rust 1.92 minimum).
- Actix-webHTTP server for the API, RSS feeds and federation endpoints, with actix-cors, rate limiting and tracing middleware.
- ActivityPubFederation with other instances through the activitypub_federation crate in the crates/apub/* crates.
- LettreSMTP email with pooled rustls connections; templates are translated with rosetta-i18n.
- markdown-itRenders user Markdown with plugins for spoilers, sub/superscript and ruby text.
- PostgreSQLOnly database; migrations directory holds hundreds of timestamped Diesel migrations, many in PL/pgSQL.
- DieselORM and query builder (diesel and diesel-async), with diesel_ltree for comment trees and per-view crates in crates/db_views.
- MokaIn-process cache used by the schema and utils crates.
- DockerMulti-stage build with cargo-chef layer caching, Debian runner, non-root user, port 8536.
- NginxReverse proxy configuration shipped for the Docker Compose deployment.
- PrometheusMetrics exported through actix-web-prom and the prometheus crate in the routes crate.
- Woodpecker CICI pipeline defined in .woodpecker.yml; no GitHub Actions workflows are present.
- JestTypeScript API and federation tests in api_tests/ that run several Lemmy instances against each other.
Lemmy architecture diagram
Open SVGDiagram as text
- Web and mobile clients (HTTP API) → Reverse proxy (Nginx): HTTPS
- Other instances (ActivityPub) → Reverse proxy (Nginx): inbox
- Reverse proxy (Nginx) → lemmy_server (Rust · Actix Web)
- lemmy_server (Rust · Actix Web) → Database (PostgreSQL · Diesel): Diesel
- lemmy_server (Rust · Actix Web) → Federation send (activitypub_federation): activities
- Federation send (activitypub_federation) → Other instances (ActivityPub): deliver
- lemmy_server (Rust · Actix Web) → Email (SMTP · Lettre): notify
Key architectural decisions
5 decisions- 01
Dozens of small crates, one per database view
The workspace in Cargo.toml lists crates/db_views/post, comment, community, person, notification, modlog, report_combined and many more as separate crates next to db_schema, api, apub and routes, so a change to one query view recompiles only the crates that depend on it.
- 02
Federation as its own crate family
crates/apub/apub, activities, objects and send isolate ActivityPub handling, built on the activitypub_federation crate that crates/server also depends on, so inbound activities, object conversion and outbound delivery are separated from the local API.
- 03
PostgreSQL does real work through migrations
migrations/ contains hundreds of timestamped Diesel migrations from 2019 onwards and PL/pgSQL is the second-largest language in the repository, so counters, triggers and tree logic live in the database; diesel_ltree supports comment trees.
- 04
TypeScript types generated from Rust structs
Crates such as db_schema, routes and utils expose a ts-rs feature, which derives TypeScript definitions from the Rust API types for client libraries, keeping the API contract in one place.
- 05
Two API generations served side by side
crates/api/routes and crates/api/routes_v3 are separate workspace members wired into lemmy_server, so older clients keep working on the v3 routes while the current API evolves.
How Lemmy is built
How Lemmy is structured
This repository is the Lemmy backend. The web UI is not part of the source tree. The root Cargo.toml declares a large workspace (version 1.0.0-beta.2, edition 2024) whose crates fall into a few families:
| Path | Role |
|---|---|
crates/server |
The lemmy_server binary that wires everything together |
crates/api/* |
api, api_crud, api_common, api_utils, plus routes and routes_v3 for two API generations |
crates/apub/* |
ActivityPub federation: apub, activities, objects, send |
crates/db_schema, db_schema_file, diesel_utils |
Diesel schema, models and helpers |
crates/db_views/* |
One crate per read model: posts, comments, communities, notifications, modlog, reports and more |
crates/routes |
Non-API HTTP: RSS feeds, Prometheus metrics, local image routes |
crates/email, crates/utils |
Email delivery and shared utilities (config, Markdown, rate limiting) |
migrations/ |
Hundreds of timestamped Diesel migrations |
api_tests/ |
TypeScript and Jest API and federation tests |
docker/ |
Dockerfile, Compose file, Nginx and PostgreSQL configs, deploy scripts |
Backend & APIs
The server runs on Actix Web. crates/server/Cargo.toml pulls in actix-web, tracing-actix-web, reqwest-middleware with reqwest-tracing for outbound calls, and clap for the CLI. On x86_64 it uses tikv-jemallocator as the allocator. crates/routes adds actix-cors, actix-web-prom (Prometheus metrics), the rss crate for feeds and clokwerk for scheduled jobs. crates/utils holds rate limiting (actix-extensible-rate-limit), Hjson config parsing (deser-hjson), markdown-it rendering with spoiler, sub, sup and ruby plugins, and clearurls to strip tracking parameters from links.
Two API generations live side by side, crates/api/routes and crates/api/routes_v3. A ts-rs feature on several crates generates TypeScript types from Rust structs for client libraries.
Data & persistence
PostgreSQL is the only store, accessed with Diesel and diesel-async (crates/db_schema/Cargo.toml). diesel_ltree models comment trees, diesel-uplete handles combined update-or-delete operations, and moka caches hot data in process. PL/pgSQL is the repository's second-largest language: migrations/ goes back to 2019, and much counting and trigger logic lives in the database rather than in Rust. Read paths are split into many crates/db_views/* crates, each owning the queries for one view.
Realtime / collaboration
Federation is the "realtime" layer. The crates/apub/* crates use the activitypub_federation crate to receive activities in an inbox, turn them into local objects and deliver outgoing activities to followers on other instances. api_tests/run-federation-test.sh and prepare-drone-federation-test.sh start several instances and test federation end to end.
Build, test & deploy
- CI runs on Woodpecker (
.woodpecker.yml). There are no GitHub Actions workflows. docker/Dockerfileusescargo-chefto cache dependency builds, buildslemmy_serverin release or debug mode, and runs it as a non-root user on a slim Debian image, exposing port 8536.- The release profile uses
lto = "fat"andcodegen-units = 1. The dev profile drops debug info for faster builds. cliff.tomlgenerates changelogs with git-cliff.
Self-hosting notes
docker/ contains everything for a Compose deployment: docker-compose.yml, nginx.conf as the reverse proxy, customPostgresql.conf for tuning, lemmy.hjson for instance config, and docker_db_backup.sh and docker_update.sh for operations. Configuration defaults are documented in config/defaults.hjson.
What to copy (and what not to)
Copy:
- One crate per read model (
db_views/*), which keeps compile times and ownership manageable in a large Diesel codebase. - Federation isolated in its own crates, so protocol changes do not ripple through the local API.
- Generate client types from server structs (
ts-rs) instead of maintaining them by hand. - Ship the operational scripts (backup, update, proxy config) with the code.
Don't copy blindly:
- Putting much logic in PL/pgSQL triggers is fast but harder to test and review than Rust.
- Dozens of workspace crates suit a long-lived project. A new app should start with a few and split when compile times demand it.
For an Actix-based stack compared with Axum, see Actix Web and Axum.
Sources & repo audit
- Workspace Cargo.toml (members, profiles)
- crates/server/Cargo.toml (lemmy_server binary)
- crates/db_schema/Cargo.toml (Diesel, ltree, ts-rs)
- crates/routes/Cargo.toml (RSS, metrics, CORS)
- docker/Dockerfile
Independent analysis of repository at github.com/LemmyNet/lemmy. Spotted an inaccuracy? Use the claim form to request a correction.
Maintainer? Add the architecture badge to your README
[](https://stackitfast.com/project/lemmy) Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Lemmy's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Lemmy" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Lemmy**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Lemmy
- **What It Does**: Lemmy is a decentralised, federated link aggregator and forum similar to Reddit, with a Rust backend on Actix Web, PostgreSQL through Diesel, and ActivityPub federation between independently run instances.
- **Domain & Category**: Federated Link Aggregator & Forum
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Lemmy splits its Rust backend into many small crates (per database view, API, ActivityPub, email) over one PostgreSQL schema with heavy migrations, so federation, the local API and queries evolve separately while a single binary serves an instance.
- **Live Website Reference**: https://join-lemmy.org
- **Source Repository**: https://github.com/LemmyNet/lemmy
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Rust, Actix-web, Diesel, PostgreSQL, ActivityPub, Tokio, Prometheus, Docker, Nginx, TypeScript, Jest
- **Primary Language(s)**: Rust, PLpgSQL, TypeScript
- **License of the reference repo**: AGPL-3.0
- **Backend & APIs**: Rust — Backend language for the lemmy_server binary and all workspace crates (edition 2024, Rust 1.92 minimum).; Actix-web — HTTP server for the API, RSS feeds and federation endpoints, with actix-cors, rate limiting and tracing middleware.; ActivityPub — Federation with other instances through the activitypub_federation crate in the crates/apub/* crates.; Lettre — SMTP email with pooled rustls connections; templates are translated with rosetta-i18n.; markdown-it — Renders user Markdown with plugins for spoilers, sub/superscript and ruby text.
- **Data & persistence**: PostgreSQL — Only database; migrations directory holds hundreds of timestamped Diesel migrations, many in PL/pgSQL.; Diesel — ORM and query builder (diesel and diesel-async), with diesel_ltree for comment trees and per-view crates in crates/db_views.; Moka — In-process cache used by the schema and utils crates.
- **Infrastructure & deploy**: Docker — Multi-stage build with cargo-chef layer caching, Debian runner, non-root user, port 8536.; Nginx — Reverse proxy configuration shipped for the Docker Compose deployment.; Prometheus — Metrics exported through actix-web-prom and the prometheus crate in the routes crate.; Woodpecker CI — CI pipeline defined in .woodpecker.yml; no GitHub Actions workflows are present.; Jest — TypeScript API and federation tests in api_tests/ that run several Lemmy instances against each other.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/LemmyNet/lemmy @ 8d83bcf)
1. **Dozens of small crates, one per database view**: The workspace in Cargo.toml lists crates/db_views/post, comment, community, person, notification, modlog, report_combined and many more as separate crates next to db_schema, api, apub and routes, so a change to one query view recompiles only the crates that depend on it.
2. **Federation as its own crate family**: crates/apub/apub, activities, objects and send isolate ActivityPub handling, built on the activitypub_federation crate that crates/server also depends on, so inbound activities, object conversion and outbound delivery are separated from the local API.
3. **PostgreSQL does real work through migrations**: migrations/ contains hundreds of timestamped Diesel migrations from 2019 onwards and PL/pgSQL is the second-largest language in the repository, so counters, triggers and tree logic live in the database; diesel_ltree supports comment trees.
4. **TypeScript types generated from Rust structs**: Crates such as db_schema, routes and utils expose a ts-rs feature, which derives TypeScript definitions from the Rust API types for client libraries, keeping the API contract in one place.
5. **Two API generations served side by side**: crates/api/routes and crates/api/routes_v3 are separate workspace members wired into lemmy_server, so older clients keep working on the v3 routes while the current API evolves.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (PostgreSQL, Diesel, Moka): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Lemmy
What is Lemmy written in?
The Lemmy backend is written in Rust on Actix Web, with Diesel and diesel-async for PostgreSQL and the activitypub_federation crate for federation. TypeScript in the repository is used for API and federation tests in api_tests/.
What database does Lemmy use?
PostgreSQL only. The repository carries hundreds of Diesel migrations since 2019, many written in PL/pgSQL, and uses the ltree extension through diesel_ltree for comment trees.
How does Lemmy federate with other servers?
Through ActivityPub. The crates/apub crates (apub, activities, objects, send) receive activities from other instances, convert them into local objects and deliver outgoing activities, built on the activitypub_federation crate.
How do I self-host Lemmy?
The repository ships a docker/ directory with a Dockerfile, docker-compose.yml, an Nginx config, a custom PostgreSQL config, a lemmy.hjson config and backup and update scripts. The server image listens on port 8536.
Does Lemmy use Actix or Axum?
Actix Web. lemmy_server and lemmy_routes depend on actix-web with actix-cors, actix-web-prom for Prometheus metrics, tracing-actix-web and actix-extensible-rate-limit.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- HyperswitchClassicOpen-Source Payments Orchestration · 20+ peopleShares Rust · Actix-web · Diesel
- MeilisearchClassicSearch Engine · 20+ peopleShares Rust · Actix-web · Tokio
- crates.ioClassicPackage Registry · 1M+ MAUShares Rust · Diesel · PostgreSQL
- Actix WebClassicRust Web Framework · 1M+ MAUShares Rust · Actix-web · Tokio
- VaultwardenClassicLightweight Self-Hosted Password Vault · Solo / 2-5 peopleShares Rust · PostgreSQL · Docker
- AppFlowyHybridLocal-First Privacy Workspace · 6-20 PeopleShares Rust · Tokio · Docker