Free and open source — read every line of it

Team chat you actually own.

Fluid Chat is a free, open source alternative to Slack. Channels, DMs, threads, reactions, files, search and presence — hosted for you, or running on your own server against your own Postgres.

No credit card. No sales call. No seat count.

$0
per seat, forever
message history
1
hard dependency: Postgres
~2 min
to a running workspace

What you get

The features you use every day. None of the ones you don’t.

Fluid Chat is not a toy clone. It is the working half of Slack — the messaging, awareness and search that a team lives in — built properly and shipped in full.

Channels, DMs and threads

Public and private channels, a channel browser, 1:1 and group DMs up to nine people, and threads with reply counts, participant facepiles and “also send to channel”.

  • Archived channels
  • Deterministic group DMs
  • Thread following

Realtime that degrades gracefully

Writes go over HTTP, reads and events over WebSocket. Typing indicators, presence and live updates arrive instantly — and if the socket dies, the app keeps working.

  • Optimistic sends
  • Redis fan-out
  • Idempotent delivery

Unreads worth trusting

Unread counts, mention badges, a “new messages” divider and mark-unread from any message. The activity feed collects mentions, thread replies, reactions and keyword hits.

  • All unreads view
  • Keyword highlights
  • Quiet hours

Files, pins and Later

Drag, drop or paste files with inline image rendering and per-conversation file lists. Pin what matters, save messages to Later, set reminders, schedule sends for the morning.

  • Permalinks
  • Scheduled send
  • Message forwarding

Slash commands and webhooks

Nineteen slash commands cover the day-to-day, and incoming webhooks let CI, alerting and scripts post into a channel under their own app identity.

  • /remind · /dnd · /status
  • Per-channel integrations
  • App identities

A client people want to use

Light and dark themes, comfortable or compact density, ⌘K quick switcher, full keyboard shortcuts, custom emoji, sidebar sections — and a drawer layout that works on a phone.

  • ⌘K quick switcher
  • 12h/24h clocks
  • Responsive by default
Plus:Message editingSoft deletesMarkdown & code fences@here / @channelUser groupsCustom emojiSkin tonesDrafts & sentSidebar starringPer-channel muteCustom status + expiryDesktop notificationsSoundsSession managementWorkspace railInvite links↑ to editDeep links
Audit logAcme · owners & admins
2mchannel.private_converted#pricing
1hmember.role_changedalan → admin
3hretention.updated#incidents · 90d
1dinvite.link_createdexpires in 7d
2dexport.completedworkspace · 2.4 GB
Seat limitsRead-only modeDefault channelsPosting policyInvite expiryData export

Administration

Grown-up controls, without the enterprise tier.

The governance features other tools reserve for the plan above yours ship in the box, because there is no plan above yours.

Roles that mean something
Owner, admin, member and guest. Guests are scoped to the channels they’re added to — they can’t browse, join, invite or wire up integrations.
Retention you set, per channel
Workspace defaults with per-channel overrides, enforced by the background worker rather than by hoping people delete things.
Exports that survive you
JSONL plus CSV plus a file manifest. Greppable, diffable, and readable without Fluid Chat — messages store stable entity tokens, so renames never rewrite history.
An audit log for the awkward questions
Who changed the posting policy, who converted the channel to private, who removed the member — with the workspace-scoped queries to prove it.

Comparison

The same workday, a very different bill.

The messaging your team already knows — without the history limit, the per-seat invoice, or a cloud you don’t control.

 
Fluid Chatself-hosted
Slack FreeSlack paid
Message historyUnlimitedLast 90 daysUnlimited
Cost per person$0$0Monthly, per seat
Where your data livesYour serverTheir cloudTheir cloud
Source codeAll of it, open
Threads & reactions
Search operators
Guest accounts
Audit logHigher tiers
Custom retention policies
Full data exportLimited
Incoming webhooks
Huddles, voice & video
Native mobile appsResponsive web
SSO / SAML

Slack plan details are summarised from Slack’s published plans and can change — check slack.com/pricing for current terms. Slack is a trademark of Salesforce; Fluid Chat is not affiliated with them.

Pricing

Free. Not free-for-now, free-for-everything.

All 91 features are in the free product, because there is no other product. Nothing is held back for a plan that costs money, because there is no plan that costs money.

The only plan
$0per person
per month

Every feature, for everyone on your team, with no limit on how long you keep your history. There is no second tier to move up to — this is the whole product.

No credit card. No sales call. No seat count.

Unlimited, and never counted

  • People in your workspace
  • Messages you send
  • Message history you keep
  • Files you upload
  • Channels you create
  • Integrations you connect
  • Admin and governance features
  • API calls you make

Things that do not exist here

  • No per-seat invoice
  • No 90-day history limit
  • No feature gated behind a tier
  • No trial that expires
  • No credit card, ever
  • No sales call

Self-host

Boring infrastructure, on purpose.

Postgres is the only hard dependency. Redis is optional — you need it once you run more than one app process. There is no proprietary datastore to learn and nothing to phone home to.

Everything in containers
# clone, configure, run$ git clone https://github.com/azianmike/fluid-chat.git$ cd fluid-chat && cp .env.example .env$ docker compose up  app       ready on http://localhost:3000  realtime  websockets on :3001  worker    jobs running  postgres  migrations applied
Or from source
$ cp .env.example .env$ npm install$ npm run db:migrate$ npm run dev        # app on :3000$ npm run realtime   # websockets on :3001$ npm run worker     # scheduled jobs# the first workspace you create makes you its owner,# with #general and #random ready to go.

Next.js 15

App and API. One thin adapter over a typed server router.

Postgres

The only hard dependency. Messages, search index, everything.

Socket.IO

A small realtime server for presence, typing and event relay.

A worker

Scheduled sends, reminders, retention, exports, email.

Install guide ·Docs for SMTP, S3/MinIO, HTTPS, backup, restore and upgrade ship in the repo

Questions

The obvious ones, answered.

Is it actually free, or free-until-you-grow?

Free. You run it on your own hardware, so there are no seats to count, no licence keys and nothing to buy. The seat-limit and billing fields in the schema exist for anyone who wants to run Fluid Chat as a hosted service — they’re inert in a self-hosted install.

Can I import my Slack history?

Not yet — a Slack importer isn’t built. Fluid Chat exports its own data as JSONL, CSV and a file manifest, so getting data out is solved; getting Slack’s data in is the open piece. It’s a good first contribution if you need it.

What does it need to run?

Node 20+, Postgres 14+, and a place to put uploads. Redis is optional and only becomes necessary once you run more than one app or realtime process, at which point realtime events fan out over Redis pub/sub instead of a direct HTTP post.

Does it work on a phone?

Yes — the client uses a drawer layout that makes the whole app usable on a small screen. There are no native iOS or Android apps, and that’s a deliberate scope decision rather than a roadmap item.

How safe is my data?

It never leaves your server. Passwords are hashed with Argon2, every query is workspace-scoped through permission helpers rather than ad-hoc filters, and guests are confined to the channels they’re added to. Retention, exports and the audit log are yours to configure.

What happens if the websocket server goes down?

The app keeps working. Writes go over HTTP and realtime is treated as an accelerator, not a dependency — you lose live updates and typing indicators, not the ability to send and read messages.

Can I extend it?

That’s the design. Adding an endpoint is a route entry plus a service function, messages store stable entity tokens so renames never rewrite history, and the client renders from DTOs so the wire format is a deliberate contract.

Something not covered? Open an issue.

Move your team off the meter.

Start free in your browser, or clone it onto your own Postgres — either way, your company owns every message in it.