# Centrifuge trades a WebSocket for emulation when a proxy will not pass one through

> Centrifuge is a Go library for real-time messaging that puts WebSocket, HTTP-streaming and EventSource behind one protocol schema, adds message recovery so a reconnecting client does not lose publications, and is pre-v1, so a minor version bump can break your API. It requires Go 1.26 and is the engine behind Centrifugo and Grafana Live.

**centrifugal/centrifuge** — Real-time messaging library for Go. The simplest way to add feature-rich and scalable WebSocket support to your application. The core of Centrifugo server.

- Repository: https://github.com/centrifugal/centrifuge
- Website: https://pkg.go.dev/github.com/centrifugal/centrifuge
- Stars: 1,492 · Forks: 123
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/centrifugal-centrifuge

## The same protocol over four transports

The distinctive thing about Centrifuge is that the transport is not the protocol. A single strict Protobuf schema, with code generation for both JSON and Protobuf serialisation, describes messages; the client reaches it over WebSocket, over HTTP-streaming, or over EventSource, and the library treats those as interchangeable.

WebSocket is the obvious one. For environments where it fails, the project ships its own WebSocket emulation layer in the browser over HTTP-streaming with JSON or Protobuf, and over EventSource with JSON. The reason it needs an emulation layer at all is the sticky sessions problem: a WebSocket is a long-lived connection bound to one server node, so any load balancer without connection affinity sends the reconnecting client to a different node and the session is lost. EventSource and HTTP-streaming are ordinary HTTP requests that a proxy can balance freely, so emulating the WebSocket API on top of them removes the affinity requirement in a distributed deployment.

There is also experimental support for WebSocket over HTTP/2 under RFC 8441, and the option to register a custom transport, which is how Centrifugo adds WebTransport.

Unidirectional use is supported without the SDKs at all, with examples for gRPC, EventSource, HTTP-streaming and a unidirectional WebSocket. That matters for the common case of server-to-client pushes where the client never speaks back; you can emit JSON over SSE and skip the SDK entirely.

The topic list naming both `sse` and `eventsource`, alongside `http-streaming` and `websocket`, reflects that the transport list is a first-class part of the design rather than an afterthought.

## Recovery, history and the client contract

Real-time messaging fails in a specific way: the connection drops and the client reconnects into a gap. Centrifuge's answer is a recovery mechanism for channels that survives PUB/SUB delivery problems, short network disconnects and node restart.

The surrounding primitives are what make that possible. History for channels is described as ephemeral streams with size and TTL retention, so a channel has a bounded buffer of recent messages rather than unbounded storage. Cache channels deliver the latest publication from history to a client at the moment it subscribes, which closes the window between subscribing and receiving. Delta compression using the Fossil algorithm reduces bandwidth for publications inside a channel, which is the common shape when a client subscribes to a channel that receives frequent updates to the same object.

Presence information lists active clients in a channel, and join and leave events report clients going online and offline. Channel subscriptions exist on both the client and the server side, so a server can force a client into a channel it did not ask for, which is how an administrator pushes a user into a notification channel.

The client SDKs cover browser, Node.js and React Native with centrifuge-js, plus Go, Dart and Flutter, native iOS with Swift, native Android and general Java, Python on top of asyncio, and a C# SDK marked work in progress for .NET including MAUI, Blazor and Unity. The stated reason for having them at all is that they abstract framing, reconnect with backoff, timeouts and multiplexing channel subscriptions over a single connection. All follow one behaviour spec, which is what stops a browser client and a Flutter client from behaving differently after a reconnect.

One detail deserves attention for compliance work: the SDKs and protocol run over JSON, so what crosses your network is application data in cleartext unless you terminate TLS in front of it.

## Redis sharding, Sentinel, Cluster, and Valkey

Horizontal scale is a stated built-in, and the specific mechanisms are named rather than vague.

Broadcasts go out over Redis PUB/SUB with consistent sharding, with Redis Sentinel and Redis Cluster support, and the project describes its Redis communication layer as heavily optimised. Non-blocking broadcasts use individual queues per client connection, which is the mechanism that stops a slow client from holding up a broadcast to everyone else.

The repository's `docker-compose.yml` spins up a test environment. It defines a single `redis` service, a `cluster` service that launches three Redis nodes on ports 7001 to 7003 and creates the cluster, and a `sentinel` service running a master on 6380 with two replicas on 6381 and 6382 plus the Sentinel process on 26379. Then it defines the same three shapes again for `valkey` and `valkey-cluster`, the Valkey-compatible fork, on port 16379 and 17000 upward. The image tags are parameterised by `REDIS_VERSION` and `VALKEY_VERSION` variables.

That compose file is worth reading as a statement of intent. The library is tested against standalone Redis, Redis Cluster, Redis Sentinel and Valkey in both single-node and cluster form, which is a much broader matrix than most Go messaging libraries will commit to in CI.

The broker is replaceable. `broker.go` and `broker_memory.go` sit beside `broker_redis.go` and `broker_redis_scripts.go`, with the memory broker as the zero-dependency default, and the README states you can register a custom PUB/SUB broker and presence manager. The Lua scripts in `broker_redis_scripts.go` are the reason a cluster-compatible Redis works: multi-key operations in a sharded deployment need server-side atomicity.

The Go module adds `rueidis` as the Redis client, Prometheus instrumentation via `client_golang`, `cel.dev/cel-go` for the client-supplied publication filters, `fdelta` for delta compression, `otter` as a cache, `udecimal` for decimal handling, and the protocol module itself at 0.23.1.

## What pre-v1 costs you, and what it buys

The README opens with a warning that should shape your adoption decision: this library has no v1 release and the API may change.

The specific policy is spelled out. Before the v1 release, patch version updates only have backwards compatible changes and fixes, while minor version updates can have backwards-incompatible API changes. The master branch can contain unreleased code, and only the last two Go minor versions are officially supported.

That is a coherent policy, not sloppiness. Pre-1.0 semantic versioning is used precisely so that breaking changes can go in minor versions, and the patch-versus-minor split means you get bug fixes without migration work. The cost is that you cannot express a long-lived compatibility promise to your own users, and that a dependency update is a review task rather than a merge.

The two-Go-minor support window is the other constraint. Applications must therefore account for the library's two-minor Go support window. For an application pinned to a long-lived Go version, that is a real constraint: your Go upgrade schedule and the library's become coupled.

The repository layout shows how mature the implementation is despite the pre-v1 label. Alongside the core `client.go`, `config.go`, `controller.go`, `hub.go` and `emulation.go` there are `client_keyed.go`, `client_shared_poll.go`, `client_map.go` and `client_experimental.go`, each with its own test file, plus a `client_lifecycle_fuzz_test.go`, which is fuzz testing on client lifecycle behaviour. Handlers are split by transport: `handler_websocket.go`, `handler_http_stream.go` and `handler_sse.go`, each with a matching test. The presence of `changelog.md`, `SECURITY.md`, `AGENTS.md` and `CLAUDE.md` documents several aspects of project development.

The `Makefile` is minimal, with an `update-deps` target that runs a script, so building and testing go through the standard Go tooling rather than a build system of its own.

## Library or server, and who should not use it

The relationship between Centrifuge and Centrifugo is the first practical question, and the README answers it: Centrifuge was decoupled into a separate library from Centrifugo at some point, and Centrifugo remains the main product of Centrifugal Labs.

The README identifies Centrifugo as Centrifugal Labs' main product and says Centrifuge is its core library. It also notes that Centrifuge was later decoupled into a separate library.

The library route gives you full control over auth, since it supports native authentication over HTTP middleware or custom token-based schemes such as JWT, and it lets you register custom brokers, presence managers and transports. The cost is that everything above the protocol becomes your problem.

Three situations argue against the library specifically. If your clients are all browsers on networks where WebSockets work reliably and you only need server-to-client push, plain HTTP streaming with server-sent events is a fraction of the dependency and no protocol schema to maintain. If you need a stable API contract across years, the pre-v1 policy makes Centrifugo the lower-risk route because the server boundary is more stable than the library's Go API.

## Licence, provenance and what to check before you commit

Licensing is MIT, with the LICENSE file at the repository root, so embedding the library in a commercial Go product carries no copyleft obligation and no attribution requirement beyond retaining the notice.

The provenance is unusually strong evidence for a pre-v1 library, and it is worth weighing properly rather than as marketing. Grafana uses Centrifuge to power its Grafana Live subsystem for streaming data to panels. The README says Grafana Live uses the library to stream data to dashboards, showing that it is used in a production project.

Before committing, three checks are worth doing in this order. First, the network path: confirm your clients can hold a WebSocket through whatever proxy or load balancer sits in front of them, and if not, confirm the emulation layer is acceptable in your clients' browsers. Second, the recovery semantics: read how message recovery interacts with your channel history TTL, because a TTL shorter than your typical disconnect window means a reconnecting client can legitimately miss messages. Third, the Go version: confirm `go 1.26.0` in the module matches your toolchain, and note the two-minor support window against your upgrade schedule.

There is also a Redis decision to make. The memory broker means you can start with a single node and no Redis at all, which is the right way to evaluate the library, and moving to Redis later is a configuration change rather than a rewrite.

## Conclusion

Centrifuge fits Go teams that need bidirectional real-time messaging, client SDKs and recovery after reconnects. Consider its pre-v1 API policy and two-minor Go support window before adoption, and verify whether simpler unidirectional transports meet your needs. Verify first whether your network path permits WebSockets at all, because the fallback transports exist precisely because it often does not.

## FAQ

### Is the Centrifuge Go API stable?

Not yet. The README states the library has no v1 release and the API may change. Patch updates before v1 carry only backwards compatible changes and fixes, while minor updates can contain backwards-incompatible API changes, and the master branch can hold unreleased code.

### Which transports does Centrifuge support?

WebSocket with JSON or binary Protobuf, plus its own WebSocket emulation layer over HTTP-streaming and EventSource, experimental WebSocket over HTTP/2 under RFC 8441, and the option to register a custom transport. Unidirectional use is also possible over gRPC, EventSource, HTTP-streaming and WebSocket without the SDKs.

### What Go version does Centrifuge require?

The go.mod declares `go 1.26.0`. Only the last two Go minor versions are officially supported by the library, so a long-lived Go version is worth checking against before you adopt it.

### Which Redis configurations does Centrifuge support?

Redis PUB/SUB with consistent sharding, Redis Sentinel and Redis Cluster, plus Valkey in single-node and cluster form. The docker-compose.yml in the repository defines standalone Redis, a three-node cluster, a Sentinel setup with a master and two replicas, and the equivalent Valkey services.

### How does Centrifuge handle a client that reconnects?

With a message recovery mechanism for channels, backed by channel history described as ephemeral streams with size and TTL retention, and cache channels that deliver the latest publication from history when a client subscribes. Recovery is stated to survive PUB/SUB delivery problems, short disconnects and node restart.

### What is the difference between Centrifuge and Centrifugo?

Centrifuge is the Go library, and Centrifugo is the server built from it and described as Centrifugal Labs' main product. The README notes Centrifuge was decoupled into a separate library from Centrifugo at some point. Choose Centrifugo for a ready server, Centrifuge to embed real-time messaging in your own Go binary.

## Sources

- [centrifugal/centrifuge on GitHub](https://github.com/centrifugal/centrifuge)
- [License: MIT](https://github.com/centrifugal/centrifuge/blob/master/LICENSE)
- [Project website](https://pkg.go.dev/github.com/centrifugal/centrifuge)
- [README](https://github.com/centrifugal/centrifuge/blob/master/README.md)
- [Releases](https://github.com/centrifugal/centrifuge/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/centrifugal-centrifuge
