Open-source team chat you run yourself: channels, threads, calls and integrations, with the messages staying on your own infrastructure.
Build me the team chat I actually need instead of a paid Mattermost tier: channels, threads and search, with retention and single sign-on. Read this first: Mattermost is open source and the free version is genuinely capable — the fee buys compliance export, retention policies, single sign-on and support. Build this when the team is small and specific, and note the one part that is not free either way: mobile push needs a relay, because a phone will only accept a notification from a service registered with the platform. STACK - Node 20+ with Fastify, server-rendered HTML with vanilla JS for the live parts - SQLite through better-sqlite3, WAL mode, with FTS5 for search - WebSockets for delivery, with a polling fallback - Caddy in front THE DATA MODEL - users: id, email, username, display_name, avatar_path, status, timezone, is_active, created_at, last_seen_at - channels: id, kind, name, slug, purpose, header, created_by, is_archived, created_at — public, private, or a direct message - memberships: channel_id, user_id, role, joined_at, last_read_message_id, notify_level, muted_until - messages: id, channel_id, user_id, parent_id, body_md, body_html, edited_at, deleted_at, created_at, pinned_at - attachments: id, message_id, path, sha256, mime, bytes, width, height, thumb_path - reactions: message_id, user_id, emoji - mentions: message_id, user_id, kind — resolved at write time, so the mention list is a lookup rather than a scan - read state per user per channel, which is what makes chat usable - retention_policies: id, scope, scope_id, keep_days, applies_to — messages, files, or both - audit: id, actor_id, action, target, at — append-only DELIVERY - WebSocket per connected client, subscribed to their channels - A message is written to the database first, then broadcast. Never the other way round, or a client sees something that does not exist after a crash - Every message carries a client-generated identifier so a resend after a dropped connection is deduplicated, and the sender's own optimistic copy is reconciled rather than duplicated - On reconnect the client asks for everything since its last known message id, and gets it in order. That single endpoint is what makes a chat feel reliable on a train - Presence in memory, never in the database — it changes constantly and is worthless a second later THREADS AND READING - Replies form a thread on a root message; the channel shows a compact summary with the reply count and the participants - Read state per channel and per thread, so a thread you are following is unread while the channel is not - Unread separators, jump to the first unread, and mark all read — the three controls people use every day - Keyboard for everything: next channel, next unread, reply, edit last, search SEARCH - FTS5 over message bodies, with filters by channel, author, date, and whether it has a file - Search results must respect permissions, checked in the query rather than filtered afterwards - Search inside a thread, and jump to the message in context NOTIFICATIONS - Levels per channel: all messages, mentions only, nothing, with a mute that has an end time - Desktop notifications through the browser, email digests for what was missed, and a quiet-hours setting per person in their own zone - Mobile push is the honest gap. A phone accepts notifications only from a service registered with the platform's push provider, which means either a relay somebody else runs or registering your own application. Say so in the README, and note that sending the message content through a relay is a privacy decision — send only 'you have a message' and let the app fetch it RETENTION AND EXPORT - A policy per channel or globally: keep messages and files for N days, then delete - Deletion is real, including attachments on disk, and it is recorded that it happened - Export a channel or the whole workspace as JSON with the attachments, in one command — for compliance, and because being able to leave is a property worth having - Legal hold on a channel, exempting it from retention, with the hold logged ACCESS - Single sign-on through OIDC, which is the only sane answer for staff accounts, with magic links as a fallback - Sessions revocable centrally, with a device list per user - Private channels genuinely private: membership checked on every read path, default deny - Guest accounts limited to named channels FILES - Uploads streamed to disk, type from content, size capped, stored by hash outside the web root - Served through a permission check, never a guessable path - Images thumbnailed, EXIF stripped OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SESSION_SECRET, OIDC_*, SMTP_URL, HASH_SALT - Migrations on boot, each once - The WebSocket layer in its own process, so a busy channel cannot slow the rest - Nightly backup off the machine, restore script — this holds the team's institutional memory - Health endpoint WHAT MATTERS MOST Reconnection and read state. Build the since-message-id endpoint and per-channel read tracking first, then use it on a bad connection for a week. Chat lives or dies on whether you can trust that you have seen everything, and every other feature is downstream of that. Give me the repository, migrations, .env.example, a seed workspace, and a README with deploy steps behind Caddy and the push notification situation stated plainly.
What you lose
- Compliance export, retention policies and single sign-on on the paid tier
- Support when a message store needs recovering
- Mobile push, which needs a relay you would otherwise operate
If you would rather not build
- Rocket.Chat, similar and open
What it costs
as published on their pricing page
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $10/mo | — | — |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Mattermost
$0The product itself, free to self-host with the team edition.
mattermost/mattermostfree · open source
Zulip
$0Open team chat organised by topic, which scales better in writing.
zulip/zulipfree · open source
Why this verdict
our own opinion · changed only by a person
78/100
Verdict yes at 78. Self-hosting is well trodden; mobile push is the one thing that is not obvious until you hit it.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Mattermost
answered from the record above
Is Mattermost free?
No — the plan we track is $10 a month. Professional at around $10 per user per month billed monthly; the team edition is free to self-host.
Can you replace Mattermost by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 78 out of 100, build time one session. Read what you lose before you decide.
How much does Mattermost cost?
$10 a month on Professional — $120 a year. Recorded 10 Aug 2026.
What do you lose by replacing Mattermost?
Compliance export, retention policies and single sign-on on the paid tier; Support when a message store needs recovering; Mobile push, which needs a relay you would otherwise operate. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Mattermost?
Yes: Mattermost, Zulip. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

