Skip to content

Choosing a backend

Gerasimos (Makis) Maropoulos edited this page Oct 6, 2026 · 2 revisions

When to use this page

  • You're picking between Redis and NATS for Scale out.
  • You already use one of them and want to confirm it'll work.
  • You want a starting point for your own benchmark.

TL;DR

Use Redis unless you have a specific reason not to.

If you already run Redis for caching or sessions, the operational delta is near zero. NATS is the better choice if you want a smaller dependency, are already running it for service-to-service messaging, or want simpler clustering.

Either backend will saturate a single neffos instance long before it becomes the bottleneck for most chat / notification / live-update workloads.

Decision matrix

Question Redis NATS
Already in our stack? Often yes. Less common.
Operational overhead Familiar to most ops teams; single binary; rich tooling. Tiny binary (<20MB), simpler config, but less institutional muscle memory.
Memory footprint at idle ~few MB. Grows with key space. neffos uses none. ~few MB. neffos uses none.
CPU at high pub/sub rate Single-threaded pub/sub dispatcher; can become CPU-bound on large fan-outs. Multi-threaded; tends to scale better with cores.
Clustering cluster mode (sharded keys); neffos uses Clusters []string config. Gossip-based; just point each neffos instance at any node.
Auth requirepass, ACLs, TLS. NKey, JWT, mTLS.
Persistence RDB/AOF; neffos does not use it. JetStream; neffos does not use it.
Cross-DC Run a separate Redis per DC; bridge with a custom relay. Built-in cluster gossip across DCs.
Local dev story docker run --rm -p 6379:6379 redis. docker run --rm -p 4222:4222 nats.

What neffos actually needs from the broker

Both backends use only the pub/sub primitive, not the persistence or queue features:

  • Subscribe to a per-connection channel (for To:-targeted messages).
  • Subscribe to a per-namespace channel.
  • Publish a serialized neffos Message to the right channel.
  • Subscribe to a per-Ask channel for replies.

That means JetStream / RDB / cluster persistence are unused. Don't over-provision storage; do provision CPU and network for pub/sub fan-out.

Quick start

Redis

import "github.com/kataras/neffos/stackexchange/redis"

exc, err := redis.NewStackExchange(redis.Config{
    Network:     "tcp",
    Addr:        "127.0.0.1:6379",
    Password:    "",        // or os.Getenv("REDIS_PASSWORD")
    DialTimeout: 5 * time.Second,
    MaxActive:   10,        // pool size
}, "my-app")               // channel prefix, unique per neffos app
if err != nil { log.Fatal(err) }

server.UseStackExchange(exc)

Cluster mode:

exc, err := redis.NewStackExchange(redis.Config{
    Clusters: []string{"r1:6379", "r2:6379", "r3:6379"},
}, "my-app")

Pick a unique channel prefix per neffos app. If two unrelated apps share one Redis with the same prefix, they'll receive each other's broadcasts.

NATS

The stack exchange package is also named nats, like the official client, so alias one of the two imports:

import (
    natsexc "github.com/kataras/neffos/stackexchange/nats"
    "github.com/nats-io/nats.go"
)

exc, err := natsexc.NewStackExchange("nats://localhost:4222")
if err != nil { log.Fatal(err) }

server.UseStackExchange(exc)

With auth:

exc, err := natsexc.NewStackExchange("",
    nats.UserInfo("user", "pass"),
    // or nats.UserCredentials("/path/to/user.creds")
    // or nats.Secure(tlsConfig)
)

Set a unique subject prefix per neffos app:

exc.SubjectPrefix = "my-app.neffos"

Failure-mode comparison

What happens during a broker outage?

Scenario Redis NATS
Broker down at startup NewStackExchange returns error. Same.
Broker dies after startup go-redis reconnects its pub/sub connections automatically; messages published during the outage are lost. NATS client reconnects automatically; messages published during the outage are lost.
Slow broker Publishes block briefly; can backpressure callers. Same.
Network partition Each instance still serves its local clients; cross-instance traffic is lost during the partition. Same.

Neither backend persists in-flight broadcasts in the default configuration. If you need durable broadcast (e.g. "every connected user must eventually see this notification"), persist it in your own store first and re-broadcast on reconnect.

Benchmark guidance

Numbers vary wildly with message size and fan-out, but a few rules of thumb:

  • A single Redis instance can push ~100K small pub/sub messages per second on commodity hardware.
  • A single NATS server can push ~5–10x that for the same workload.
  • The neffos in-process broadcaster (no StackExchange) is faster than either. Scale-out is a network round-trip you pay for cross-instance delivery.

If you're approaching broker throughput limits, first check whether you can shard by namespace (each namespace is a separate channel/subject) before changing brokers.

If neither backend fits (a different broker, an in-process bus for tests), implement the StackExchange interface yourself. See Writing a custom StackExchange.

See also

Clone this wiki locally