Search for Firebase alternatives and you get a list of backends: Supabase, Appwrite, PocketBase, Amplify. Fine, if what you built on Firebase is a to-do app. If what you built is chat, that list answers a question you didn’t ask.
Last year I made the case against Firebase for chat and then never supplied the list. This is the list, and each row says the thing a feature grid never says: what you have to rebuild when you leave, and what the bill is shaped like once you have.
You are not migrating a database. You are migrating a message router, a presence system and an archive, and each alternative makes you pay for those three somewhere else.
What You’re Actually Leaving
Firebase’s trick is that it never asked you to think about delivery. A message is a write; delivery is other clients noticing the write. That is the whole design, and it is why the first afternoon is magical and the second year isn’t.
The Realtime Database caps at 200,000 simultaneous connections per database, and the same page says what to do about it: “To scale beyond any of these limits, use multiple databases.” Sharding your users across databases is your problem, by design. Firestore doesn’t natively support presence; the documented solution is to run a Realtime Database alongside it and mirror connection state through Cloud Functions. Two databases and a function, to draw a green dot.
The bill is shaped like storage. The Realtime Database is $5 per GB stored and $1 per GB downloaded after the free tier; Firestore charges per document read and write, 50,000 reads a day free. A busy group chat is a lot of reads of the same document. Nothing here is priced per message, per connection or per user, because Firebase has no idea your writes are messages.
So the three things every alternative has to replace are: fan-out (who gets this message, on which node), presence (who is here, and who just dropped off a train), and the archive (what did I miss, and the inbox view that shows it). Keep that triple in mind. Every option below moves it somewhere, and the price of the move is the migration.
Figures and prices are as of 2026-09-18 and will drift; the shapes won’t.
The Options, by What They Make You Rebuild
| Option | Closest to Firebase in | You rebuild | Bill shape |
|---|---|---|---|
| Supabase Realtime | The listen-to-rows model | Inbox, archive queries | Per plan, capped by connections |
| Stream, Sendbird, Twilio | Nothing; it’s a product | Your data model, your clients | Per MAU, with connection caps |
| Ably (and its family) | Channels, like database paths | Archive beyond 30 days, inbox | Per message and connection-minute |
| ejabberd, MongooseIM, Prosody | Nothing; it’s a protocol | Clients, auth bridge, ops | Your servers, or a support contract |
| Matrix (Synapse) | Nothing; rooms are replicated | Everything, plus federation | Your servers; AGPL |
| Rocket.Chat, Mattermost, Zulip | Nothing; it’s a Slack | Nothing to embed; it’s an app | Your servers, or their cloud |
| Centrifugo, Socket.IO | The “just push it” feeling | Archive, receipts, offline, inbox | Your servers, and your weekends |
Supabase Realtime: the nearest shape
If your Firebase chat is “a messages table and a listener”, Supabase Realtime is the same idea with Postgres under it. Its three features map directly: Broadcast, Presence and Postgres Changes, which is more than Firestore gives you, because presence is in the box.
The catch is in the limits table: 200 concurrent connections on the free plan, 500 on Pro, 10,000 on Pro without a spend cap or on Team, at 100 to 2,500 messages a second. Ten thousand concurrent is a real product; it is not a large one. What you rebuild is the archive: your history is a Postgres table now, which is better than Firestore’s document reads, and the inbox is a query you write.
Pick this if your users are already in Postgres and your peak concurrency fits in the table. The migration is the smallest on this page.
Stream, Sendbird, Twilio: buy the feature
These are chat as a product: SDKs, an inbox, typing indicators, read receipts, moderation, all done. Nothing of Firebase survives the move; you import your history into their model and rewrite the client against their SDK.
The bill is per monthly active user, and the number to read is the concurrent-connection cap, not the MAU. Stream’s free tier is 1,000 MAU and 100 concurrent connections, and the Start plan is $399 a month billed annually for 10,000 MAU and 500 concurrent. Sendbird’s Starter is $349 a month annually for 5,000 MAU, with peak concurrent connections capped at 5% of the MAU limit, which is 250 people online at once. Twilio Conversations starts at $0.05 per active user per month, the first 200 free.
Five percent concurrency is fine for a marketplace where chat is a side channel. It is not fine for anything people leave open. If your users sit in the app, price the enterprise tier before you fall in love with the SDK.
Ably and the pub/sub family: channels with presence
Ably, PubNub and Pusher sell the layer Firebase gave you for free: a channel you publish to and subscribe from, with presence attached. Ably’s free tier is 6 million messages a month and 200 concurrent connections; Standard is $29 a month plus $2.50 per million messages and $1 per million connection-minutes. Presence and history are included, with history kept one day on the free plan and 30 days on Standard.
The migration is smaller than it looks, because a channel is a database path with the storage removed. What you rebuild is everything the storage was doing: the archive past 30 days, the inbox, group membership, who is allowed in which channel. You will end up with a database beside it. It just won’t be the router any more.
ejabberd, MongooseIM, Prosody: own the protocol
This is the option the previous post argued for, so here is what it costs.
XMPP gives you the triple as specs rather than features: XEP-0045 for rooms, XEP-0313 for the archive, XEP-0085 for typing, XEP-0333 for read markers, XEP-0280 for keeping your phone and laptop in sync. Presence is in the name.
Three servers, three postures. ejabberd is GPLv2, claims 2 million concurrent users per node with clustering out of the box, speaks XMPP, MQTT, SIP and Matrix, and has a Business Edition with three-year support windows if you’d rather pay than learn. MongooseIM is the ejabberd fork I’ve run for the last two projects: also GPLv2, 2.5 million online users on one node in its own load tests, 10 million across a cluster, backed by MySQL, PostgreSQL or Cassandra, and it adds the two extensions that matter for a product: Inbox, which is the server keeping your conversation list with unread counts so the client doesn’t assemble it from the roster and the archive, and MUC Light, group chat for clients that can’t keep a presence session open, because, as its spec puts it, “Modern mobile applications do not rely on presence information, as it can frequently change.” Prosody is MIT, at 13.0.6, and aims “to be easy to set up and configure, and efficient with system resources”, which is exactly what it is: the right server for one team’s chat, the wrong one for a million strangers'.
What you rebuild is everything, once. Clients speak XMPP over WebSocket, so the client rewrite is real. Auth is a bridge, and MongooseIM ships one: its JWT method verifies a token the client presents over SASL PLAIN, checking the signature and the exp, iat and nbf claims against a key you configure, so whatever issues your users’ tokens today keeps issuing them and the chat server only checks. Operations are Erlang-shaped, which is a compliment about uptime and a warning about hiring. The migration itself is dual-write for a few weeks, then a backfill of the old history into MAM, then flipping the clients.
The bill is your servers. There is no per-MAU line, which is the whole point once you have MAUs.
Matrix: a different bet, not a successor
Synapse gives you rooms replicated across every participating server, federation as a first-class feature and end-to-end encryption designed in. It also gives you the consequence of that design: presence is the thing Matrix had to switch off, and I wrote a whole post on why routing stanzas and replicating rooms diverge exactly there.
The licence changed. Synapse and Dendrite moved to AGPLv3 in December 2023, with Element selling an alternative licence to anyone who wants to modify the server without publishing the modifications. For a chat feature inside a proprietary product, read that twice before you deploy.
Pick Matrix if federation or E2EE is the product. Do not pick it because it is “the modern XMPP”. It isn’t; it is the other fork in the road.
Rocket.Chat, Mattermost, Zulip: when you wanted a Slack
Half the people searching for Firebase alternatives for chat actually want a self-hosted Slack or Discord, not a chat feature. If that is you, stop building. Rocket.Chat is MIT with the enterprise directories under a separate licence; Mattermost ships compiled builds under MIT, source under AGPLv3, admin tooling under Apache 2.0, and a commercial licence on request; Zulip is Apache 2.0, full stop, which after the other two reads like a relief.
You rebuild nothing, because you embed nothing. You run an application. The migration is an export and an import, and the bill is a server or their cloud plan.
Centrifugo and Socket.IO: roll your own, with help
Socket.IO is where most Firebase refugees land first, and its own docs state the two things you inherit the moment you run a second node: sticky sessions, so that “all requests associated with a particular session ID reach the process that originated them”, and an adapter, Redis or otherwise, because broadcasting across processes needs “some way of passing messages between processes or computers”. That is your router, and you now maintain it.
Centrifugo is the honest middle: an Apache 2.0 server that does the router for you, with WebSocket, SSE, HTTP streaming, WebTransport and gRPC on the client side, presence, channel history and message recovery on reconnect built in, and Redis, PostgreSQL or NATS to run across nodes. Its own figure is a million WebSocket connections and 30 million delivered messages a minute on one server-class machine; treat that as a ceiling you’ll never see, but a ceiling.
What you rebuild is everything Firebase also didn’t give you: the archive beyond the channel history window, read receipts, offline delivery, the inbox, group membership. The bill is your servers and, more than any other row, your weekends.
How to Choose
Four questions, in this order.
Is chat the product, or a feature? A feature goes to Supabase Realtime or a managed API. A product goes to XMPP, or to Matrix if federation is why it exists. Nothing in between survives contact with a growing user base without turning into one of those two anyway.
What is your peak concurrency? Not MAU. Every managed row on this page caps concurrent connections, and the caps are small: 100, 250, 500. Count the people who leave the app open, then read the pricing pages. Firebase capped you at 200,000 and you never noticed; the alternatives will make you notice at 250.
Who owns the data? The previous post covered the GDPR deletion problem when history lives in a JSON tree you don’t control. Managed APIs move that problem to their data processing agreement; self-hosting moves it to you. Neither is free. One is auditable.
Can you hire for it? Erlang operations are stable and rare. A Postgres team can run Supabase or Centrifugo tomorrow. A team that has never run a WebSocket server should not learn on ejabberd, and should not learn on Socket.IO in production either.
What I’d Do
For a chat feature in a product with a small team and users already in Postgres: Supabase Realtime, until the connections table says otherwise. The migration is a week and the rollback is trivial.
For a product where chat is the product: MongooseIM, knowing the cost. Inbox on the server, MAM for history, clustering for the day you need it, and deployments that run for months without anyone touching them. The client rewrite is real, the Erlang is real, and after that the bill is servers, not users.
For a self-hosted Slack: Zulip, because its licence is one line, and stop writing chat code.
For everything else, Centrifugo over Socket.IO, because the router is the part you will get wrong and it’s the part they got right.
Firebase’s gift was that you never had to choose a router, a presence system or an archive. Its trap was the same sentence. Every alternative on this page makes you choose all three, and the good news is that choosing is the whole migration: once the triple has a home, the rest is moving data.
Pick the row whose bill you can predict at ten times your current users. That’s the only feature grid that matters.
