Centrifugo: a self-hosted pub/sub server for WebSocket, SSE and HTTP streaming
Scalable real-time messaging server in a language-agnostic way. Self-hosted alternative to Pubnub, Pusher, Ably, socket.io, Phoenix.PubSub, SignalR. Set up once and forever.
At a glance
- What is it?
- Centrifugo is an Apache-2.0 Go server that sits between your backend and connected clients, speaking WebSocket, SSE, HTTP-streaming, GRPC and WebTransport. It is a strong fit when you want one real-time transport layer across several languages, and a poor fit when you need durable log semantics.
- Who is it for?
- Adopt Centrifugo if you want one real-time transport layer shared by a JavaScript frontend, a Dart or Swift mobile client and an HTTP or GRPC backend, and you are willing to run Redis, PostgreSQL or NATS underneath for multi-node scale. Do not adopt it if you need a durable, replayable event log with consumer offsets; that is Kafka or NATS JetStream territory, not a channel pub/sub server.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 26, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Centrifugo solves, and who it is for
Every application that shows live data eventually writes the same code twice: once for the WebSocket connection, and once for the business logic that decides who receives what. Centrifugo separates those two. The README describes it as "a PUB/SUB server on top of modern real-time transports", and the design goal is that your backend never holds a client socket. It publishes to a channel over HTTP or GRPC; Centrifugo holds the connections and fans the message out.
The intended audience is a team with a mix of client platforms. The README lists official SDKs for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python asyncio, Go, and a .NET/MAUI/Unity SDK marked WIP. That list is the actual selling point: a Flutter app and a browser app can subscribe to the same channel without either team writing reconnect logic. The README also notes a unidirectional mode (WebSocket, SSE, HTTP-streaming, GRPC) that needs no SDK at all, which matters when the client is something you cannot install a library into.
How the pub/sub mechanism and the server API fit together
The data flow has two independent paths. On the client side, a subscriber opens a connection and subscribes to a channel; the README calls this "channel subscription multiplexing over a single connection", so one socket can carry many subscriptions. On the server side, your backend calls Centrifugo's HTTP or GRPC API to publish into that channel. Centrifugo does not call your business logic to ask what to send; you push, it delivers.
Authentication is where the two paths meet. The README gives two mechanisms: JWT, and a proxy-like mode where Centrifugo makes a request back to your backend to check the connection. The JWT path means your backend signs a token and Centrifugo validates it locally, which keeps the connection handshake off your application servers. The proxy path inverts that and puts your backend in the connection path, which is simpler to reason about but adds a dependency on your service being up when clients connect.
For multi-node deployments the README lists Redis (including Redis Cluster and Redis-compatible stores such as AWS ElastiCache, Valkey, KeyDB and DragonflyDB), PostgreSQL, or NATS as the broker that carries publications between Centrifugo nodes. The repository's docker-compose.yml provisions NATS with `-js` and PostgreSQL 16 with `wal_level=logical`, which shows the two backends the project exercises in its own test setup. The go.mod file also pulls in Kafka (franz-go), Google Cloud Pub/Sub, Azure Service Bus and AWS SQS, so those appear as consumer integrations rather than as the pub/sub broker.
Installing Centrifugo with Docker and publishing your first message
The README's quick start runs Centrifugo with its embedded admin UI. The two insecure flags remove authentication so you can try it locally; the README states plainly that they are "for local trial only, never use in production".
docker run -it --rm -p 8000:8000 centrifugo/centrifugo:latest centrifugo \
--client.insecure --admin.enabled --admin.insecureAfter the container starts, open http://localhost:8000. The README says the admin UI is where you can "watch live connections and publish messages into channels", so the first real use is to publish a message from the UI and see it arrive without writing a backend at all.
The container image itself is built from the repository's Dockerfile, which is Alpine 3.24 with ca-certificates and a single `centrifugo` binary copied to /usr/local/bin/centrifugo, running as a non-root user created with UID 1000 and GID 1000. That is a small image with no shell tooling, which is fine for running and awkward if you expect to exec in and debug.
For anything beyond the trial, the README points to the installation instructions and quickstart tutorial on centrifugal.dev, and to the client protocol spec for the no-SDK transports. Production configuration is not in the README; the config surface is exposed through Cobra and Viper flags and files, and the repository ships a docker-compose.yml for local multi-service setups.
What Centrifugo deliberately does not do
Centrifugo is a pub/sub server, not a message log. The README advertises "hot message history in channels" with recovery on reconnect and a cache recovery mode that delivers the latest publication immediately on subscription. Hot means bounded: this is a recent-message buffer for reconnect gaps, not a retained stream you can replay from an arbitrary offset. If your requirement is "every consumer processes every event exactly once, in order, days later", Centrifugo is the wrong layer, and the README's own comparison targets (Kafka, NATS, RabbitMQ) are where that work belongs.
The second boundary is operational. The README's scalability story depends on Redis, PostgreSQL, or NATS being present and healthy. A single Centrifugo node without a broker is a single point of failure for every connected client, and the documentation does not describe a built-in clustering mode that avoids an external broker. You are choosing a broker whether or not you think of it as a choice.
Third, WebTransport is labelled experimental in the README's transport list. Treat it as something to evaluate, not something to build a product requirement on. The same caution applies to the .NET/MAUI/Unity SDK, which the README marks WIP.
Centrifugo compared with socket.io and with Kafka
Against socket.io, the difference is architectural rather than feature-by-feature. socket.io is a Node.js library that lives inside your application process; your server code and your socket handling share a runtime and a deployment. Centrifugo is a separate binary that your backend talks to over HTTP or GRPC. That separation is why the SDK list spans JavaScript, Dart, Swift, Java, Python and Go: the transport layer is not tied to one language's runtime. The cost is a second service to deploy, monitor and secure, plus a broker if you run more than one node.
Against Kafka, the difference is semantics. Kafka retains an ordered log and consumers track offsets; Centrifugo holds subscriptions and delivers to whoever is connected now, with a bounded history buffer for reconnects. The README positions Kafka as an asynchronous consumer source for transactional outbox and CDC patterns, which is the honest framing: Kafka feeds Centrifugo, it does not replace it. If you already run Kafka and need live browser delivery, the two are complementary. If you picked Centrifugo hoping to drop Kafka, you will miss the log.
Licence, maintenance and the cost of staying current
Centrifugo is Apache-2.0, which permits commercial use, modification and redistribution provided you keep the licence and notices intact. That is a permissive licence with no copyleft obligation on your own code. It says nothing about whether the maintainers will accept your patch, and it is not legal advice; if you embed Centrifugo in a product, have your own counsel read the LICENSE file.
The repository is not archived, and the last push was on 2026-09-20. Releases are frequent and granular: v6.9.4 on 2026-09-07, v6.9.5 on 2026-09-13, v6.9.6 on 2026-09-14. Frequent patch releases mean the upgrade cost is mostly small and routine, but the module path is versioned (`github.com/centrifugal/centrifugo/v6`) and go.mod requires Go 1.26.0, so a v5 to v6 move is a deliberate migration rather than a patch bump. The repository keeps a CHANGELOG.md at the top level; that file, not the README, is where upgrade steps live. Budget for reading it before each minor bump, and pin a version in your image tag rather than tracking `latest` as the quick start does.
Editorial conclusion
Adopt Centrifugo if you want one real-time transport layer shared by a JavaScript frontend, a Dart or Swift mobile client and an HTTP or GRPC backend, and you are willing to run Redis, PostgreSQL or NATS underneath for multi-node scale. Do not adopt it if you need a durable, replayable event log with consumer offsets; that is Kafka or NATS JetStream territory, not a channel pub/sub server. Before committing, verify the transport you actually need (WebTransport is marked experimental), confirm which broker you can operate, and check the v6 upgrade notes in CHANGELOG.md against the version you plan to pin.
Frequently asked questions
What is Centrifugo?
Centrifugo is an open-source, language-agnostic real-time messaging server. It delivers messages to connected clients over WebSocket, HTTP-streaming, Server-Sent Events, GRPC and WebTransport, and your backend publishes into channels through its HTTP or GRPC API.
Is Centrifugo free and open source?
Yes. The repository is licensed under Apache-2.0, and the README describes Centrifugo as an open-source scalable real-time messaging server.
Is Centrifugo open source?
It is. The licence file in the repository is Apache-2.0, which permits commercial use and modification as long as the licence and notices are preserved.
How does Centrifugo compare with socket.io?
socket.io runs inside your application process, while Centrifugo is a separate server that your backend reaches over HTTP or GRPC. That separation is what lets the same Centrifugo instance serve JavaScript, Dart, Swift, Java, Python and Go clients.
How does Centrifugo compare with Kafka?
They solve different problems. Kafka is a retained, ordered log with consumer offsets, while Centrifugo is a channel pub/sub server with hot message history for reconnect recovery. The README positions Kafka as an asynchronous consumer source that can feed Centrifugo, not as a replacement for it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/centrifugal-centrifugo)