Discourse vs Lemmy: Which Forum to Self-Host?
Quick Verdict
Discourse and Lemmy solve fundamentally different problems. Discourse is a traditional threaded forum built for long-form discussion, support communities, and knowledge bases. Lemmy is a federated link aggregator modeled after Reddit, built for voting on links and short-form commentary across the fediverse. If you want a support forum or community discussion board, pick Discourse. If you want a Reddit-style experience that federates with other instances via ActivityPub, pick Lemmy.
Choosing between them is less about which is “better” and more about which interaction model fits your community.
Overview
Discourse launched in 2013 as a modernization of the classic forum format. Built on Ruby on Rails by Jeff Atwood (co-founder of Stack Overflow), it has become the de facto standard for self-hosted community forums. Companies like Mozilla, Docker, and Netlify run their communities on Discourse. It is polished, mature, and heavy on resources.
Lemmy appeared in 2019 as part of the fediverse movement. Written in Rust with an Actix-web backend, it implements the ActivityPub protocol so communities on one Lemmy instance can interact with communities on other instances — and with Mastodon, Kbin, and other fediverse platforms. It gained significant traction during the 2023 Reddit API pricing controversy. It is lightweight, opinionated, and federation-first.
Feature Comparison
| Feature | Discourse | Lemmy |
|---|---|---|
| Architecture | Ruby on Rails, PostgreSQL, Redis, Sidekiq | Rust (Actix-web), PostgreSQL, pictrs (images) |
| Content model | Threaded discussion topics in categories | Link posts and text posts in communities, upvote/downvote |
| Federation | No (single-instance only) | Yes, ActivityPub — federate with other Lemmy/Kbin/Mastodon instances |
| Plugin ecosystem | Extensive — 200+ official and community plugins | Minimal — no plugin system, features are built into core |
| Search | Full-text search built in, with advanced filters | Basic built-in search, improving with each release |
| Moderation tools | Mature — trust levels, auto-moderation, flagging, review queues, slow mode | Solid — per-community mods, site-wide admins, report system, slur filters |
| SSO / Authentication | DiscourseConnect SSO, OAuth2, SAML, LDAP via plugin | OAuth2, basic username/password, no SAML/LDAP |
| Mobile apps | Official progressive web app, community iOS/Android apps | Jerboa (official Android), Voyager, Thunder, Eternity (community apps) |
| API | Full REST API, well-documented | Full REST API, auto-generated OpenAPI docs |
| Themes & customization | Theme system with CSS/HTML overrides, component themes | Limited — basic color theming, no layout customization |
| Email integration | Reply via email, mailing list mode, digest emails | Notifications only, no email reply |
| Real-time updates | Yes, via MessageBus (WebSocket-like) | Yes, via WebSocket |
| Internationalization | 50+ languages | 40+ languages |
| License | GPL-2.0 | AGPL-3.0 |
| Minimum RAM | 2 GB (3+ GB recommended) | 200-300 MB |
Installation Complexity
Discourse
Discourse has an opinionated installation process. The official method uses a custom Docker launcher (launcher) rather than standard Docker Compose. However, you can run it with Docker Compose if you manage the services yourself. The setup requires PostgreSQL, Redis, and Sidekiq workers. Initial configuration happens through a discourse.conf or environment variables, followed by a web-based setup wizard.
The biggest complexity is resource overhead. Discourse genuinely needs 2+ GB of RAM to run comfortably. On a 1 GB VPS, it will swap constantly and become unusable. Budget for a 4 GB machine if you want headroom.
Create a docker-compose.yml:
services:
discourse-db:
image: postgres:16.2-alpine
restart: unless-stopped
environment:
POSTGRES_USER: discourse
POSTGRES_PASSWORD: change-this-strong-password
POSTGRES_DB: discourse
volumes:
- discourse-db-data:/var/lib/postgresql/data
networks:
- discourse-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U discourse"]
interval: 10s
timeout: 5s
retries: 5
discourse-redis:
image: redis:7.2-alpine
restart: unless-stopped
volumes:
- discourse-redis-data:/data
networks:
- discourse-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
discourse:
image: discourse/discourse:3.4.5
restart: unless-stopped
depends_on:
discourse-db:
condition: service_healthy
discourse-redis:
condition: service_healthy
environment:
# Database connection
DISCOURSE_DB_HOST: discourse-db
DISCOURSE_DB_PORT: "5432"
DISCOURSE_DB_NAME: discourse
DISCOURSE_DB_USERNAME: discourse
DISCOURSE_DB_PASSWORD: change-this-strong-password
# Redis connection
DISCOURSE_REDIS_HOST: discourse-redis
DISCOURSE_REDIS_PORT: "6379"
# Site settings — CHANGE THESE
DISCOURSE_HOSTNAME: forum.example.com
DISCOURSE_DEVELOPER_EMAILS: [email protected]
# SMTP — required for account creation
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: "587"
DISCOURSE_SMTP_USER_NAME: your-smtp-user
DISCOURSE_SMTP_PASSWORD: your-smtp-password
DISCOURSE_SMTP_ENABLE_START_TLS: "true"
volumes:
- discourse-data:/var/www/discourse/public
- discourse-logs:/var/www/discourse/log
ports:
- "8080:80"
networks:
- discourse-net
volumes:
discourse-db-data:
discourse-redis-data:
discourse-data:
discourse-logs:
networks:
discourse-net:
Note: The official Discourse team recommends their own
discourse_dockerlauncher over plain Docker Compose. This Compose setup works but may require additional tweaks for plugin installation and upgrades. SMTP is mandatory — Discourse will not let you create accounts without working email.
Start the stack:
docker compose up -d
Access the setup wizard at http://your-server:8080.
Lemmy
Lemmy is far simpler to deploy. The stack is a Rust backend, a separate frontend (lemmy-ui), PostgreSQL, and pictrs for image hosting. Total memory footprint is under 500 MB for everything combined.
Create a docker-compose.yml:
services:
lemmy-db:
image: postgres:16.2-alpine
restart: unless-stopped
environment:
POSTGRES_USER: lemmy
POSTGRES_PASSWORD: change-this-strong-password
POSTGRES_DB: lemmy
volumes:
- lemmy-db-data:/var/lib/postgresql/data
networks:
- lemmy-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U lemmy"]
interval: 10s
timeout: 5s
retries: 5
pictrs:
image: asonix/pictrs:0.5.16
restart: unless-stopped
environment:
PICTRS__SERVER__API_KEY: change-this-pictrs-api-key
PICTRS__MEDIA__VIDEO_CODEC: vp9
PICTRS__MEDIA__GIF__MAX_WIDTH: "256"
PICTRS__MEDIA__GIF__MAX_HEIGHT: "256"
PICTRS__MEDIA__GIF__MAX_AREA: "65536"
PICTRS__MEDIA__GIF__MAX_FRAME_COUNT: "400"
volumes:
- pictrs-data:/mnt/sled-repo
- pictrs-files:/mnt/files
networks:
- lemmy-net
lemmy:
image: dessalines/lemmy:0.19.8
restart: unless-stopped
depends_on:
lemmy-db:
condition: service_healthy
environment:
LEMMY_DATABASE_URL: postgres://lemmy:change-this-strong-password@lemmy-db:5432/lemmy
# Lemmy reads config from this file
LEMMY_CONFIG_LOCATION: /etc/lemmy/lemmy.hjson
volumes:
- ./lemmy.hjson:/etc/lemmy/lemmy.hjson:ro
networks:
- lemmy-net
lemmy-ui:
image: dessalines/lemmy-ui:0.19.8
restart: unless-stopped
depends_on:
- lemmy
environment:
# Internal API URL — the UI talks to the backend over the Docker network
LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536
# External URL — what users see in their browser
LEMMY_UI_LEMMY_EXTERNAL_HOST: lemmy.example.com
LEMMY_UI_HTTPS: "true"
ports:
- "1234:1234"
networks:
- lemmy-net
volumes:
lemmy-db-data:
pictrs-data:
pictrs-files:
networks:
lemmy-net:
Create a lemmy.hjson configuration file alongside the Compose file:
{
# The domain of your instance — CHANGE THIS
hostname: "lemmy.example.com"
# Bind address for the API
bind: "0.0.0.0"
port: 8536
# Whether to enable TLS (handle this at the reverse proxy)
tls_enabled: false
# pictrs image hosting config
pictrs: {
url: "http://pictrs:8080/"
api_key: "change-this-pictrs-api-key"
}
# Database connection
database: {
uri: "postgres://lemmy:change-this-strong-password@lemmy-db:5432/lemmy"
}
# Email — optional but recommended
email: {
smtp_server: "smtp.example.com:587"
smtp_login: "your-smtp-user"
smtp_password: "your-smtp-password"
smtp_from_address: "[email protected]"
tls_type: "starttls"
}
# Federation — set to true to enable ActivityPub
federation: {
enabled: true
}
}
Start the stack:
docker compose up -d
Access the UI at http://your-server:1234. The first user you register becomes the site administrator.
Lemmy is dramatically easier to set up. Fewer services, lower resource requirements, and a simpler configuration surface. Discourse requires more planning, especially around SMTP (which is mandatory, not optional).
Performance and Resource Usage
This is where the difference is stark.
| Resource | Discourse | Lemmy (full stack) |
|---|---|---|
| Minimum RAM | 2 GB | 200-300 MB |
| Recommended RAM | 4 GB | 512 MB - 1 GB |
| CPU (idle) | Moderate — Ruby/Sidekiq background jobs run constantly | Low — Rust binary is extremely efficient |
| CPU (under load) | High — Rails is not known for performance | Low to moderate — Rust handles concurrency well |
| Disk (application) | ~3 GB (app + plugins + precompiled assets) | ~200 MB |
| Disk (database) | Grows with content; 1 GB+ for active communities | Grows with content; smaller footprint per post |
| PostgreSQL | Required | Required |
| Redis | Required | Not needed |
| Additional services | Sidekiq (background jobs, bundled in container) | pictrs (image hosting), lemmy-ui (frontend) |
The takeaway: You can run Lemmy comfortably on a $5/month VPS. Discourse needs at minimum a $10-15/month server, and a $20/month server for a community with any real activity. For resource-constrained home labs, Lemmy is the clear winner.
Community and Ecosystem
Discourse has a 10+ year head start. The ecosystem reflects that:
- 200+ plugins covering everything from chat integration to gamification to custom layouts
- Active Meta forum (meta.discourse.org) with years of accumulated knowledge
- Commercial hosting available from the Discourse team (for those who don’t want to self-host)
- Large corporate user base means issues get fixed quickly
- Well-documented API with extensive community-built integrations
- Professional support available through paid plans
Lemmy is younger but growing fast:
- Part of the broader fediverse ecosystem — interoperates with Mastodon, Kbin, and other ActivityPub platforms
- Active development with frequent releases
- Growing mobile app ecosystem (Jerboa, Voyager, Thunder, and others)
- Community-driven — no commercial entity behind it
- Smaller but passionate contributor base
- Federation means your instance is never isolated — users can interact with communities across the fediverse
For plugin-dependent workflows, Discourse wins decisively. If you need SSO with your existing identity provider, Akismet spam filtering, custom user fields, or chat integration, Discourse has plugins for all of it. Lemmy has no plugin system — you get what ships in the release.
For network effects, Lemmy’s federation is a killer feature. A new Discourse instance starts with zero users and zero content. A new Lemmy instance can immediately subscribe to communities on other instances, giving your users content from day one.
Use Cases
Choose Discourse If…
- You are building a support community for a product or open-source project
- You want a traditional forum with categories, topics, and threaded replies
- Long-form discussion is the primary content format
- You need mature moderation tools including trust levels and auto-moderation
- You require SSO integration with an existing identity provider (SAML, LDAP, OAuth)
- Plugin extensibility is important — you need chat, gamification, custom fields, or API integrations
- You have the server resources to run it (4+ GB RAM recommended)
- You want email integration — users replying to topics via email, digest emails, mailing list mode
- Search is critical — Discourse’s full-text search with filters is substantially better
Choose Lemmy If…
- You want a Reddit-like experience with link posts, upvotes/downvotes, and communities
- Federation matters — you want your instance to be part of the broader fediverse
- You are running on limited hardware (a Raspberry Pi 4 can handle Lemmy; it cannot handle Discourse)
- You want a link aggregator, not a discussion forum
- You care about AGPL licensing and full copyleft
- You want your community to have content from day one by federating with existing instances
- You prefer a simpler operational footprint — fewer services, less memory, easier upgrades
- You are building for a privacy-focused or decentralization-minded audience
Final Verdict
These are not competitors — they are different tools for different jobs.
If someone asks “should I run Discourse or Lemmy?” the right follow-up question is “what kind of community are you building?” A product support forum, a knowledge-sharing community, or a membership organization should run Discourse. It is more polished, more extensible, and better suited for structured, long-form discussion. The resource cost is worth it for the feature set.
A link-sharing community, a local interest group, or anyone who wants to participate in the fediverse should run Lemmy. It is lightweight, federated, and purpose-built for the Reddit-style interaction model. The lack of plugins is a real limitation, but federation is a genuine advantage that Discourse cannot match.
If you are still unsure: Discourse is the safer, more mature choice for most community-building use cases. Lemmy is the right choice specifically when you want Reddit-style mechanics or federation. Pick based on the interaction model your users expect, not on which platform is “better” in the abstract.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments