# Kaneo WebSocket Broadcasting Adapters: In-Memory and Redis Implementation Guide

> Explore Kaneo WebSocket broadcasting adapters. Learn about the InMemoryBroadcastAdapter for single instances and the RedisBroadcastAdapter for distributed systems. Enhance real-time event distribution.

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

---

**Kaneo provides two concrete WebSocket broadcasting adapters—the `InMemoryBroadcastAdapter` for single-instance deployments and the `RedisBroadcastAdapter` for distributed production environments—both implementing the `BroadcastAdapter` interface to enable real-time event distribution across clients.**

The open-source project management platform Kaneo relies on WebSocket connections to deliver real-time task updates and notifications. To accommodate different infrastructure requirements, Kaneo WebSocket broadcasting adapters abstract the message distribution layer through a clean TypeScript interface that supports both local development and scaled production deployments.

## Understanding the BroadcastAdapter Interface

At the core of Kaneo's real-time system lies the `BroadcastAdapter` interface defined in [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts). This contract standardizes how events propagate from the server to connected WebSocket clients across different deployment scenarios.

The interface requires three asynchronous methods:

- `broadcast(event: Event): Promise<void>` – Dispatches an event to all adapters subscribed to the event's specific channel.
- `subscribe(channel: string, adapter: WSAdapter): Promise<void>` – Registers a `WSAdapter` (WebSocket connection wrapper) to receive messages for a given channel.
- `unsubscribe(channel: string, adapter: WSAdapter): Promise<void>` – Removes a `WSAdapter` from a channel's subscription list.

Both concrete implementations import the `Event` type from `@kaneo/api/events` and the `WSAdapter` type from `@kaneo/api/ws`, ensuring type safety across the broadcast layer.

## In-Memory Broadcast Adapter for Local Development

The `InMemoryBroadcastAdapter` located in [`apps/api/src/ws/in-memory-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/in-memory-broadcast-adapter.ts) provides a lightweight, process-local implementation ideal for development environments and unit testing. This adapter maintains a private `Map<string, Set<WSAdapter>>` called `channelMap`, where each key represents a channel name and each value contains the set of active WebSocket connections subscribed to that channel.

When `broadcast(event)` is called, the adapter retrieves the adapter set for `event.channel` and iterates through each connection, invoking `adapter.send(event)` directly. No external dependencies are required, making this implementation perfect for single-instance deployments where all clients connect to the same server process.

```typescript
import { InMemoryBroadcastAdapter } from "@kaneo/api/ws";
import { Event } from "@kaneo/api/events";

const adapter = new InMemoryBroadcastAdapter();
const mockWS = { send: async (e: Event) => console.log(e) };

await adapter.subscribe("project-123", mockWS);

const event: Event = {
  channel: "project-123",
  data: { taskId: "456", action: "updated" }
};

await adapter.broadcast(event);

```

The adapter automatically cleans up empty channels when the last subscriber unsubscribes, preventing memory leaks in long-running development servers.

## Redis Broadcast Adapter for Production Scaling

For distributed deployments where multiple Kaneo API instances run behind a load balancer, 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) enables cross-process event propagation using Redis Pub/Sub. This implementation wraps a `RedisClientType` instance created via the `redis` package's `createClient` function.

The constructor accepts a `redisUrl` string and establishes the Redis connection immediately. The adapter maintains local subscription state in a `subscriptions` Map while leveraging Redis to distribute events across all API instances. When `broadcast(event)` executes, it serializes the event to JSON and publishes it to the Redis channel matching `event.channel`. Incoming Redis messages trigger the private `dispatch(event)` method, which forwards the deserialized event to locally connected WebSocket adapters.

```typescript
import { RedisBroadcastAdapter } from "@kaneo/api/ws";
import { Event } from "@kaneo/api/events";

const redisUrl = process.env.REDIS_URL || "redis://localhost:6379";
const adapter = new RedisBroadcastAdapter(redisUrl);

// In instance A:
await adapter.subscribe("project-123", wsAdapter);

// In instance B:
const event: Event = {
  channel: "project-123", 
  data: { message: "Task completed" }
};
await adapter.broadcast(event);
// Instance A receives the event through Redis and forwards to its local clients

```

The adapter manages Redis subscriptions efficiently, calling `client.subscribe(channel)` only when the first local adapter subscribes to a channel, and `client.unsubscribe(channel)` when the last local adapter leaves.

## Selecting the Right Adapter for Your Deployment

Choosing between the two Kaneo WebSocket broadcasting adapters depends entirely on your infrastructure topology:

**InMemoryBroadcastAdapter** excels in containerized local development, continuous integration pipelines, and single-node deployments where horizontal scaling is unnecessary. The test suite in [`tests/api/ws/in-memory-broadcast-adapter.test.ts`](https://github.com/usekaneo/kaneo/blob/main/tests/api/ws/in-memory-broadcast-adapter.test.ts) demonstrates its usage with Vitest and mock adapters.

**RedisBroadcastAdapter** becomes essential when running multiple Kaneo API instances behind a load balancer or across Kubernetes pods. Without Redis, events broadcast from Instance A would never reach WebSocket clients connected to Instance B.

Both implementations maintain identical method signatures and behavior semantics, allowing you to switch between them by changing a single configuration line without modifying business logic.

## Summary

- The `BroadcastAdapter` interface in [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts) defines the contract for real-time event distribution with `broadcast`, `subscribe`, and `unsubscribe` methods.
- `InMemoryBroadcastAdapter` stores subscriptions in a local `Map` and serves single-instance deployments and testing scenarios.
- `RedisBroadcastAdapter` leverages Redis Pub/Sub to synchronize events across multiple Kaneo API instances for horizontal scalability.
- Both adapters use the same `Event` and `WSAdapter` types from the `@kaneo/api` package, ensuring type-safe interoperability.

## Frequently Asked Questions

### What is the BroadcastAdapter interface in Kaneo?

The **BroadcastAdapter** interface is the abstraction layer that decouples Kaneo's WebSocket event system from specific message distribution implementations. Defined in [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts), it requires three methods: `broadcast` to send events, `subscribe` to register clients to channels, and `unsubscribe` to remove them. This design allows the API server to switch between in-memory and Redis-based broadcasting without changing application code.

### How does the InMemoryBroadcastAdapter handle WebSocket subscriptions?

The **InMemoryBroadcastAdapter** maintains a private `channelMap` of type `Map<string, Set<WSAdapter>>` where each channel maps to a set of active WebSocket connections. When `subscribe(channel, adapter)` is called, it adds the adapter to the set for that channel, creating a new set if necessary. The `broadcast` method retrieves the adapter set for the event's channel and calls `send(event)` on each connection sequentially.

### When should I use the RedisBroadcastAdapter instead of the in-memory version?

Use the **RedisBroadcastAdapter** whenever you deploy multiple instances of the Kaneo API behind a load balancer or across different servers. Without Redis, WebSocket clients connected to Instance A would not receive events broadcast from Instance B because the in-memory adapter cannot share state across process boundaries. The Redis adapter solves this by publishing events to a shared Redis channel that all instances subscribe to.

### Can I implement a custom broadcast adapter for Kaneo?

Yes, any class implementing the `BroadcastAdapter` interface from [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts) will work with Kaneo's WebSocket system. Your custom implementation must provide the three async methods: `broadcast(event)`, `subscribe(channel, adapter)`, and `unsubscribe(channel, adapter)`, handling the exact type signatures using `Event` from `@kaneo/api/events` and `WSAdapter` from `@kaneo/api/ws`. This flexibility allows integration with alternative message brokers like RabbitMQ or Apache Kafka if needed.