An open‑source, self‑hosted forum starter kit. Categories, flat threads, Slate editing, RBAC with custom roles, S3 uploads, moderation queues, and pluggable adapters. Deploy on Vercel or Docker — own your community, own your data.
Hierarchical categories with public/private visibility. Flat threads with cursor pagination, slugs for SEO, and soft-deleted states. No recursive comment trees.
Slate-based editor with Markdown and HTML output. Content stored as portable JSON — no editor lock-in. Image uploads integrated directly into the editor.
Fine-grained RBAC with explicit resource:action checks. Admin-configurable custom roles from a dashboard. Category visibility gated by role or group membership.
S3-compatible presigned direct uploads for avatars and content images. Server-side hash-based filenames and path validation. Local filesystem adapter for development.
Flag system with reasons, status workflow (pending → accepted/rejected), and admin command center. Content states: active, hidden, flagged, deleted. Never hard-delete.
Pluggable storage, email, realtime, and analytics adapters. Swap providers in config — no code changes. PostgreSQL today, portable tomorrow.
Configure your forum in one file. Swap any provider — database, storage, email — by changing an import. Everything else stays the same.
// reforum.config.ts
import { createForum } from 'reforum';
import { postgres } from 'reforum/database';
import { s3 } from 'reforum/storage';
import { resend } from 'reforum/email';
export const forum = createForum({
database: postgres({
url: process.env.DATABASE_URL,
}),
storage: s3({
bucket: process.env.S3_BUCKET,
region: process.env.S3_REGION,
}),
email: resend({
apiKey: process.env.RESEND_KEY,
}),
});// Swap adapter — no code changes elsewhere
import { createForum } from 'reforum';
import { sqlite } from 'reforum/database'; // swap PG → SQLite
import { local } from 'reforum/storage'; // swap S3 → local FS
import { console as consoleAdapter } from 'reforum/email'; // noop in dev
export const forum = createForum({
database: sqlite({ path: './data/reforum.db' }),
storage: local({ directory: './uploads' }),
email: consoleAdapter(),
});Reforum ships as a Next.js app today. The adapter-first architecture keeps your domain logic, services, and API routes framework-independent — so you can migrate when you need to.
Self-host on your own infra. Reforum is adapter-first — swap storage, email, and realtime providers in config. Deploy on Vercel, Railway, Coolify, or any Docker host.
import { createForum } from 'reforum';
import { postgres } from 'reforum/database';
import { s3 } from 'reforum/storage';
import { resend } from 'reforum/email';
export const forum = createForum({
database: postgres({ url: process.env.DATABASE_URL }),
storage: s3({ bucket: process.env.S3_BUCKET }),
email: resend({ apiKey: process.env.RESEND_KEY }),
});Every feature is built around real API calls. Categories, flat threads, RBAC, presigned uploads, flag-based moderation, and pluggable adapters — all with typed, composable methods.
import { forum } from '@/lib/forum';
// List categories the current user can see
const categories = await forum.categories.list({
includePrivate: true,
});
// Create a private category for a team
await forum.categories.create({
name: 'Core Team',
slug: 'core-team',
description: 'Internal discussions for team members',
isPrivate: true,
allowedRoleIds: ['role_admin', 'role_moderator'],
});