How to Configure Redis for WebSocket Pub/Sub Broadcasting in Kaneo
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, 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 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
# .env
REDIS_URL=redis://localhost:6379
// 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
# .env
REDIS_CLUSTER_NODES=10.0.1.1:6379,10.0.1.2:6379,10.0.1.3:6379
REDIS_PASSWORD=cluster-pass
// 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 authenticationREDIS_SENTINEL_TLS— Set"true"to enable TLS for Sentinel connectionsREDIS_PASSWORD— Redis master password
# .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
// 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. The initializeWebSocketAdapter() function checks isRedisConfigured() before selecting an adapter:
// 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 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:
- Select one mode — Choose Standalone, Cluster, or Sentinel based on your infrastructure
- Set only that mode's variables — Mixing variables from multiple modes triggers the priority logic unpredictably
- Verify in
.env.sample— The sample file documents all supported variables and their formats - Restart the API —
initializeWebSocketAdapter()runs once at startup; configuration changes require a restart - 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 |
Correct parsing of each mode's environment variables |
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 |
Parses environment, resolves mode, creates Redis clients |
apps/api/src/ws/index.ts |
Initializes broadcast adapter based on Redis availability |
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
InMemoryBroadcastAdapterfor 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →