# How to Configure Redis for WebSocket Pub/Sub Broadcasting in Kaneo

> Configure Redis for WebSocket pub/sub broadcasting in Kaneo with simple environment variables. Enable reliable real-time communication effortlessly.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: how-to-guide
- Published: 2026-08-06

---

**Kaneo enables Redis-backed WebSocket broadcasting by setting a single environment variable—`REDIS_URL` for standalone, `REDIS_CLUSTER_NODES` for cluster, or `REDIS_SENTINELS` for Sentinel mode—then automatically initializing a `RedisBroadcastAdapter` on API startup.**

Kaneo's real-time collaboration layer uses a **pluggable broadcast system** that scales from single-instance development to multi-node production deployments. When the API boots, it calls `initializeWebSocketAdapter()` in [`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts), which detects Redis configuration and instantiates the appropriate adapter. This guide covers all three supported Redis modes with the exact environment variables and code paths used by the Kaneo source.

## Supported Redis Connection Modes

Kaneo's `resolveRedisMode()` function in [`apps/api/src/redis/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/redis/index.ts) supports three mutually exclusive connection strategies. The system evaluates them in **strict priority order**: Cluster → Sentinel → Standalone.

### Standalone Mode (Simplest Setup)

Use this for local development or single Redis instances.

**Required environment variable:**

- `REDIS_URL` — Full Redis connection URI

```bash

# .env

REDIS_URL=redis://localhost:6379

```

```typescript
// apps/api/src/redis/index.ts
export function resolveRedisMode(): RedisMode {
  const url = process.env.REDIS_URL;
  if (!url) {
    throw new Error(
      "REDIS_URL, REDIS_SENTINELS, or REDIS_CLUSTER_NODES must be set",
    );
  }
  return { mode: "standalone", url };
}

```

The `createRedisClient()` function passes this URL directly to `new Redis(url)`.

### Cluster Mode (Production Sharding)

Use this for horizontally sharded Redis deployments.

**Required environment variable:**

- `REDIS_CLUSTER_NODES` — Comma-separated list of `<host>:<port>`

**Optional:**

- `REDIS_PASSWORD` — Authentication for all nodes

```bash

# .env

REDIS_CLUSTER_NODES=10.0.1.1:6379,10.0.1.2:6379,10.0.1.3:6379
REDIS_PASSWORD=cluster-pass

```

```typescript
// apps/api/src/redis/index.ts
if (clusterNodes) {
  return {
    mode: "cluster",
    nodes: parseNodeList(clusterNodes, "REDIS_CLUSTER_NODES", 6379),
    password: process.env.REDIS_PASSWORD,
  };
}

```

The client is instantiated as `new Redis.Cluster(nodes, { redisOptions: { password } })`.

### Sentinel Mode (High Availability)

Use this for Redis Sentinel failover deployments with optional TLS.

**Required environment variable:**

- `REDIS_SENTINELS` — Comma-separated list of Sentinel addresses `<host>:<port>`

**Optional:**

- `REDIS_SENTINEL_MASTER_NAME` — Defaults to `"mymaster"`
- `REDIS_SENTINEL_PASSWORD` — Sentinel authentication
- `REDIS_SENTINEL_TLS` — Set `"true"` to enable TLS for Sentinel connections
- `REDIS_PASSWORD` — Redis master password

```bash

# .env

REDIS_SENTINELS=10.0.0.1:26379,10.0.0.2:26379
REDIS_SENTINEL_MASTER_NAME=mymaster
REDIS_SENTINEL_PASSWORD=secret
REDIS_SENTINEL_TLS=true
REDIS_PASSWORD=shared-pass

```

```typescript
// apps/api/src/redis/index.ts
if (sentinels) {
  return {
    mode: "sentinel",
    sentinels: parseNodeList(sentinels, "REDIS_SENTINELS", 26379),
    name: process.env.REDIS_SENTINEL_MASTER_NAME || "mymaster",
    password: process.env.REDIS_PASSWORD,
    sentinelPassword: process.env.REDIS_SENTINEL_PASSWORD,
    enableTLSForSentinelMode: process.env.REDIS_SENTINEL_TLS === "true",
  };
}

```

## How the WebSocket Adapter Initializes

The broadcast system is wired together in [`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts). The `initializeWebSocketAdapter()` function checks `isRedisConfigured()` before selecting an adapter:

```typescript
// apps/api/src/ws/index.ts
import { isRedisConfigured, getRedisPub, getRedisSub } from "@/redis";

export async function initializeWebSocketAdapter() {
  if (isRedisConfigured()) {
    // RedisBroadcastAdapter uses shared pub/sub clients
    const adapter = new RedisBroadcastAdapter(getRedisPub(), getRedisSub());
    console.log('📡 WebSockets Initialized using: "RedisBroadcastAdapter"');
    return adapter;
  }
  
  // Fallback for single-instance deployments
  const adapter = new InMemoryBroadcastAdapter();
  console.log('📡 WebSockets Initialized using: "InMemoryBroadcastAdapter"');
  return adapter;
}

```

When Redis is configured, the `RedisBroadcastAdapter` in [`apps/api/src/ws/redis-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/redis-broadcast-adapter.ts) handles cross-instance messaging:

- **Publishing**: Outbound messages are sent to a shared Redis Pub/Sub channel
- **Subscribing**: Incoming messages from other instances are forwarded to local connections via `deliverToLocalConnections()`

## Configuration Checklist

Follow these steps to enable **Redis WebSocket pub/sub broadcasting in Kaneo**:

1. **Select one mode** — Choose Standalone, Cluster, or Sentinel based on your infrastructure
2. **Set only that mode's variables** — Mixing variables from multiple modes triggers the priority logic unpredictably
3. **Verify in `.env.sample`** — The sample file documents all supported variables and their formats
4. **Restart the API** — `initializeWebSocketAdapter()` runs once at startup; configuration changes require a restart
5. **Confirm adapter selection** — Check logs for `📡 WebSockets Initialized using: "RedisBroadcastAdapter"`

## Testing Configuration Resolution

The Kaneo test suite validates mode resolution logic in two files:

| Test file | Coverage |
|-----------|----------|
| [`tests/api/redis/redis-config.test.ts`](https://github.com/usekaneo/kaneo/blob/main/tests/api/redis/redis-config.test.ts) | Correct parsing of each mode's environment variables |
| [`tests/api/redis/redis-priority.test.ts`](https://github.com/usekaneo/kaneo/blob/main/tests/api/redis/redis-priority.test.ts) | Priority enforcement (Cluster beats Sentinel beats Standalone) |

You can verify your configuration locally by setting variables and inspecting `resolveRedisMode()` output.

## Key Source Files

| File | Purpose |
|------|---------|
| [`apps/api/src/redis/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/redis/index.ts) | Parses environment, resolves mode, creates Redis clients |
| [`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts) | Initializes broadcast adapter based on Redis availability |
| [`apps/api/src/ws/redis-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/redis-broadcast-adapter.ts) | Redis Pub/Sub implementation of `BroadcastAdapter` |
| `.env.sample` | Reference for all Redis environment variables |

## Summary

- **Three Redis modes**: Standalone (`REDIS_URL`), Cluster (`REDIS_CLUSTER_NODES`), Sentinel (`REDIS_SENTINELS`)
- **Priority order**: Cluster → Sentinel → Standalone — only the first detected mode activates
- **Single client reuse**: `createRedisClient()` builds one connection used for both publishing and subscribing
- **Automatic fallback**: Without Redis config, Kaneo uses `InMemoryBroadcastAdapter` for single-instance operation
- **Verification**: Look for the `"RedisBroadcastAdapter"` log line on API startup

## Frequently Asked Questions

### What happens if I set multiple Redis mode variables?

Kaneo evaluates modes in fixed priority: **Cluster** takes precedence over **Sentinel**, which takes precedence over **Standalone**. Only the highest-priority detected mode initializes. To force a specific mode, unset variables for higher-priority modes.

### Can I use Redis for WebSocket broadcasting without code changes?

Yes. The `initializeWebSocketAdapter()` function in [`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts) automatically detects Redis configuration through `isRedisConfigured()`. No application code modification is required—only environment variables.

### How do I verify Redis WebSocket broadcasting is working?

Check API logs for the startup message: `📡 WebSockets Initialized using: "RedisBroadcastAdapter"`. If you see `"InMemoryBroadcastAdapter"` instead, your Redis environment variables are not being detected. Confirm variable names against `.env.sample` and restart the API.

### Does Kaneo support Redis ACL usernames?

The current implementation in [`apps/api/src/redis/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/redis/index.ts) uses `REDIS_URL` for standalone mode, which supports `redis://username:password@host:port` format. For Cluster and Sentinel modes, username support depends on the underlying `ioredis` version bundled with your Kaneo installation—check the `parseNodeList()` and connection options in the source for your specific release.