# neffos: a Go real-time framework built around namespaces and rooms

> neffos is a Go framework for real-time applications that gives a websocket a small object model of connections, namespace connections and rooms, with request-response semantics, error propagation, scale-out over Redis or NATS, and matching browser and Node clients. It suits a Go team that wants more than a raw socket, and it is still a pre-1.0 library with a wide API to learn.

**kataras/neffos** — A modern, fast and scalable websocket framework with elegant API written in Go

- Repository: https://github.com/kataras/neffos
- Website: http://bit.ly/neffos-wiki
- Stars: 629 · Forks: 52
- Language: Go
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/kataras-neffos

## A framework for the awkward half of websocket applications

neffos is a cross-platform real-time framework with an expressive, elegant API written in Go, and it exists to handle the tasks that a raw websocket library leaves to you.

The feature list in the documentation is the argument for it. Scale-out using Redis or NATS, with a StackExchangeCloser to release it on shutdown and NSConn.Broadcast for a same-server send. Adaptive request upgradation and server dialing. Three backends, gorilla, gobwas and coder. Acknowledgements. Namespaces. Rooms. Broadcast. Both event-driven and request-response architecture. Error awareness. Asynchronous broadcast. Heartbeat, close status codes and a message size limit. Graceful shutdown. Timeouts. Encoding. Reconnection in the JavaScript client. And a modern client API for browsers, Node.js and Go.

Read that list as a description of the failure modes. A websocket connection on its own is a byte pipe. Real-time applications need routing, a way to address many clients at once, a way to send a message and wait for an answer, a way to report a failure to the caller who asked, and a way to survive a server restart. Each of those is a design decision, and neffos makes them for you.

The project sits in the same ecosystem as the Iris web framework, and the same author is behind both, which is worth knowing when you look for the wiki and the surrounding tooling.

## One connection, many namespaces, many rooms

The object model is small enough to hold in your head, and the documentation states it in one line: one Conn per websocket, one NSConn per namespace it connects to, one Room per room it joins. Server and client sides share the same types and methods.

That last point is the design decision with the widest consequences. A namespace is a logical channel, and connecting to one of them gives you an NSConn that can send events, ask questions and join rooms. A room is a further grouping, and joining one gives you a Room with its own Send and SendObject, and a Leave that removes you from it.

The Message type is the envelope. It carries the Namespace, the Room, the Event name and the Body as a byte slice, and it carries an Err field. There is also an As method for decoding into a typed value and an Unmarshal method that takes a pointer, so the same envelope works for structured payloads.

The class diagram in the documentation makes the relationships explicit. A Conn connects to zero or more NSConn values through Connect(namespace) and can look one up with Namespace(namespace). An NSConn joins zero or more rooms through JoinRoom(name) and can look one up with Room(name) or list them with Rooms(). A Conn sends with Send(Message) and asks with Ask(ctx, Message), which returns a Message and an error, and it carries generic per-connection state through Set and Value.

The reason to model it this way is that a single websocket often carries several logically different conversations. Splitting them into namespaces means a client can subscribe to a chat channel and a notification channel on one socket without the server guessing which is which.

## Send, Ask, and the difference between an event and a question

neffos supports both an event-driven and a request-response architecture over the same connection, and the two are distinguished by which method you call on the namespace connection.

Send is fire and forget. SendObject does the same with a serialised value. Ask is the other half: it sends a message and waits for the reply, returning a Message and an error, and AskObject is the typed version with a Reply type parameter.

The example in the documentation shows the shape of a handler. A namespace is registered for a path and an event name, and the handler receives the namespace connection and the message. It parses the body, and on a parse failure it returns the error, with a comment saying it returns the parse error back to the client. Otherwise it fires a different client event with ns.Send("notify", ...) or replies with neffos.Reply(...).

That error behaviour is what the documentation calls error awareness, and it is worth more than it sounds. In a lot of real-time code, a handler that fails silently leaves the client waiting, and the only symptom is a spinner that never stops. Here, an error returned from the handler travels back as the error of the Ask on the other side, and the client can distinguish a bad request from a closed socket.

Around that sit the operational details: acknowledgements for delivery, timeouts on both ends, heartbeats, close status codes, a message size limit, graceful shutdown, and encoding. On the client side, the Go example shows the loop: it calls Ask, and if the error is a close error it breaks out of the loop, and otherwise it prints the error and continues. That is the pattern for a request-response client, and it is the one you will write most.

## Scale-out over Redis or NATS, and the closer that has to be released

The scale-out story is the one that separates a framework from a library, because a single websocket connection is bound to a single process, and a multi-instance deployment needs the instances to talk to each other.

neffos handles that with a stack exchange, and the feature list names two supported backends, Redis and NATS, with a runnable example under _examples/07-scale-out. The dependencies in the module file are the concrete list: github.com/redis/go-redis/v9 at v9.23.0 and github.com/nats-io/nats.go at v1.54.0, alongside golang.org/x/sync.

Two pieces of that deserve attention. StackExchangeCloser exists to release the stack exchange on shutdown, which sounds like a detail until you have watched a process exit while holding a Redis connection that nobody cleaned up. And NSConn.Broadcast is a same-server send, which is the fast path: a message destined for many clients on one instance does not need to go through the exchange at all, and only the cross-instance traffic pays for the distributed hop.

The repository structure backs this up. There is a stackexchange.go at the root, a stackexchange/ directory for the implementations, and the broadcaster.go file with its test sits next to it, so the broadcast path is a first-class part of the codebase rather than a bolt-on.

Worth noting for planning: the queue and cache infrastructure is not a dependency of the core. The module file lists the websocket backends, the two brokers and x/sync, and nothing else, so the framework does not drag a Redis client into your binary unless you actually use the Redis stack exchange.

## Three websocket backends, swapped at the upgrader

neffos does not implement the websocket protocol itself. It sits above one of three libraries, and the choice is visible in the import in the server example:

```go
import (
    // [...]
    "github.com/kataras/neffos"
    "github.com/kataras/neffos/gorilla"
)
```

The three backends are gorilla, gobwas and coder, and the module file pins all three: github.com/gorilla/websocket at v1.5.3, github.com/gobwas/ws at v1.4.0 and github.com/coder/websocket at v1.8.15. The repository has a directory for each, gorilla/, gobwas/ and coder/.

The integration point is the upgrader on the server side and the dialer on the client side. The server example builds the server with neffos.New(gorilla.DefaultUpgrader, ...), and the Go client dials with neffos.Dial(ctx, gorilla.DefaultDialer, "ws://localhost:8080", events). Swapping backends means swapping that one value, which is a genuinely useful property: the choice of websocket library tends to be driven by maintenance and performance considerations that change, and neffos keeps the rest of your code stable across such a change.

The same import appears on both ends of the wire, which is a small detail with a practical consequence. The server and the Go client in the documentation both use gorilla, and a mismatch between the two is a class of bug that is annoying to diagnose from a log.

## Getting a server and three clients running

Installation needs Go 1.27 or later, and the module is fetched the usual way:

```sh
go get github.com/kataras/neffos@latest
```

The server side is a namespace map, a handler per event, and a websocket server created with an upgrader. The WithTimeout option adds a read timeout and a heartbeat on top of the namespaces, in the example a 60 second read timeout and a 20 second ping interval, and the server is then mounted on an http.ServeMux and served on a port.

The browser client is a script tag and a promise, using the neffos.js distribution from a CDN, then dialing, connecting to a namespace and asking a question:

```html
<script src="https://cdn.jsdelivr.net/npm/neffos.js@0.3/dist/neffos.global.min.js"></script>
<script>(async () => {
  const conn = await neffos.dial("ws://localhost:8080", { "/v1": { notify: (ns, msg) => console.log(msg.Body) } });
  const nsConn = await conn.connect("/v1");
  await nsConn.ask("workday", "06-24-2019");
})();</script>
```

The JavaScript client for Node.js lives in its own repository, kataras/neffos.js, and it is where reconnection is handled.

For anything beyond the quick view, the documentation points at the wiki, which has a page per feature, from the first echo server to scaling out over Redis or NATS. That arrangement makes sense for a framework with this many knobs: the README shows you the shape of an application, and the wiki explains each feature on its own page.

## Where neffos is the wrong amount of framework

Three limits are worth naming, and the version history makes one of them unavoidable.

The first is that this is a pre-1.0 library with a wide surface. The releases are v0.0.22 from 2023-08-10, v0.0.23 from 2024-01-10 and v0.0.24 from 2025-03-29, and the repository is not archived with the last push on 2026-10-06. A zero major version with a 0.0.x suffix means the API is not promised to be stable, and the feature list, with its adaptive request upgradation and server dialing, suggests an ambitious design that will keep moving.

The second is the Go requirement. The module declares go 1.27, and the installation note says Go 1.27 or later is required. That is a recent toolchain, and it is a constraint on a team that has not upgraded.

The third is that the framework is much more than a socket. If your service accepts a websocket and pushes a notification, neffos is a lot of machinery: namespaces, rooms, a stack exchange abstraction, three backends, a client library in three languages and a wiki to read. The alternative in that case is to depend on a websocket library directly, which the project itself depends on, and write the handful of lines of routing you actually need. The difference in approach is that neffos pre-decides the routing model, the error model, the scale-out model and the client model for you, and the price is that you adopt all four.

For an application that genuinely has namespaces, rooms, request-response and more than one server instance, that trade is good. For anything smaller, it is overhead with a learning curve attached.

## Conclusion

Adopt neffos if your Go service needs more than a raw websocket: namespaced routing, rooms, request-response with errors returned to the caller, and horizontal scale-out over Redis or NATS, and you are prepared to follow a pre-1.0 API. Do not adopt it for a single-socket service that only needs to push messages, because the framework is much more machinery than that requires, or if your Go toolchain is older than 1.27. Verify first which of the three backends, gorilla, gobwas or coder, fits your deployment, that the JS client you use matches the server version, and that the namespace and room semantics in the wiki match how your application is structured.

## FAQ

### What is neffos and who is it for?

It is a cross-platform real-time framework with an expressive API written in Go, aimed at real-time backend and frontend applications. It provides namespaces, rooms, request-response and event-driven architectures, error awareness, scale-out over Redis or NATS, and clients for browsers, Node.js and Go.

### How do I install neffos?

Go 1.27 or later is required, then run go get github.com/kataras/neffos@latest. The module path is github.com/kataras/neffos, and the JavaScript client lives in the separate kataras/neffos.js repository.

### What are the Conn, NSConn and Room types in neffos?

There is one Conn per websocket, one NSConn per namespace the connection joins, and one Room per room it joins. A Conn can connect to namespaces and ask questions, an NSConn sends events and joins rooms, and a Room sends to its members. Server and client sides use the same types and methods.

### Which websocket backends does neffos support?

Three: gorilla, gobwas and coder, each with its own directory in the repository and its own package import such as github.com/kataras/neffos/gorilla. The backend is chosen through the upgrader on the server and the dialer on the client.

### How does neffos scale out to more than one server?

Through a stack exchange backed by Redis or NATS, with a StackExchangeCloser to release it on shutdown, and NSConn.Broadcast for sends that stay on one server. The repository dependencies include github.com/redis/go-redis/v9 and github.com/nats-io/nats.go, and there is a runnable scale-out example.

## Sources

- [kataras/neffos on GitHub](https://github.com/kataras/neffos)
- [License: MIT](https://github.com/kataras/neffos/blob/main/LICENSE)
- [Project website](http://bit.ly/neffos-wiki)
- [README](https://github.com/kataras/neffos/blob/main/README.md)
- [Releases](https://github.com/kataras/neffos/releases)

---

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