# How to Configure Redis for Caching and Pub/Sub in OpenCTI

> Learn to configure Redis for OpenCTI caching and pub/sub using environment variables for seamless real-time data updates.

- Repository: [OpenCTI Platform/opencti](https://github.com/opencti-platform/opencti)
- Tags: how-to-guide
- Published: 2026-02-19

---

**Configure Redis for OpenCTI by setting environment variables like `REDIS__MODE`, `REDIS__HOSTNAME`, and `REDIS__PORT`, then initialize the clients via `initializeRedisClients()` in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts) to enable caching and real-time pub/sub functionality.**

OpenCTI relies on Redis as a high-performance in-memory data store to handle session caching, distributed locking, and real-time GraphQL subscriptions. To configure Redis for caching and pub/sub in OpenCTI, you need to understand the client factory architecture in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts) and the environment variables that control connection behavior across single, sentinel, and cluster deployment modes.

## Redis Configuration Environment Variables

OpenCTI reads Redis connection parameters from environment variables defined in the deployment configuration. These variables control topology, authentication, TLS, and namespace prefixing.

| Variable | Default | Purpose |
|----------|---------|---------|
| `REDIS__MODE` | `single` | Deployment topology: `single`, `sentinel`, or `cluster` |
| `REDIS__HOSTNAME` | `localhost` | Host for single mode |
| `REDIS__HOSTNAMES` | — | JSON array of `host:port` for cluster or sentinel |
| `REDIS__PORT` | `6379` | Port for single mode |
| `REDIS__USERNAME` / `REDIS__PASSWORD` | — | Authentication credentials |
| `REDIS__SENTINEL_MASTER_NAME` | — | Master name required for sentinel mode |
| `REDIS__USE_SSL` | `false` | Enable TLS encryption |
| `REDIS__CA` | `[]` | Paths to CA certificates for TLS |
| `REDIS__NAMESPACE` | — | Key prefix added to every key (`REDIS_PREFIX`) |
| `REDIS__TRIMMING` | `2000000` | Max entries in Redis Stream for UI history |

The complete reference lives in [`docs/docs/deployment/configuration.md`](https://github.com/OpenCTI-Platform/opencti/blob/main/docs/docs/deployment/configuration.md).

## Redis Client Architecture in OpenCTI

The Redis integration centers on a factory function `createRedisClient` in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts). This factory adapts to your chosen deployment mode and handles TLS, authentication, and namespace prefixing automatically.

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
const redisOptions = async (provider: string, autoReconnect = false): Promise<RedisOptions> => ({
  connectionName: connectionName(provider),
  keyPrefix: REDIS_PREFIX,
  ...userPasswordAuth,
  tls: USE_SSL ? { ...configureCA(REDIS_CA), servername: conf.get('redis:hostname') } : undefined,
  retryStrategy: (times) => autoReconnect ? Math.min(times * 50, 2000) : null,
  lazyConnect: true,
  enableOfflineQueue: true,
});

```

Depending on `REDIS__MODE`, the factory instantiates:

- **Cluster**: `new Redis.Cluster(clusterNodes, clusterOpts)` with `natMap` and `scaleReads`
- **Sentinel**: `new Redis(sentinelOpts)` with master name and sentinel authentication
- **Single**: `new Redis({ ...singleOptions, db, port, host })` with direct host/port selection

## Initializing Redis Clients for Caching and Pub/Sub

During platform startup, `redisInit()` calls `initializeRedisClients()` to create four distinct Redis connections:

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const initializeRedisClients = async () => {
  const base = await createRedisClient('base', true);
  const xrange = await createRedisClient('xrange', true);
  const lock = await createRedisClient('lock', true);
  const publisher = await createRedisClient('publisher', true);
  const subscriber = await createRedisClient('subscriber', true);
  redisClients = {
    base,
    xrange,
    lock,
    pubsub: new RedisPubSub({
      publisher,
      subscriber,
      connectionListener: (err) => {
        logApp.info('[REDIS] Redis pubsub client closed', { error: err });
      },
    }),
  };
};

```

Each client serves a specific purpose:

- **`base`**: General caching operations (sessions, edit contexts, work progress)
- **`xrange`**: Range queries for UI activity streams
- **`lock`**: Distributed locking via Redlock
- **`pubsub`**: Real-time GraphQL subscriptions using `graphql-redis-subscriptions`

## Implementing Caching with Redis

OpenCTI provides helper functions in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts) for common caching patterns. The caching layer uses TTL-based keys and sorted sets for list management.

### Transaction Helper

```typescript
export const redisTx = async (client: Cluster | Redis, chain: (tx: ChainableCommander) => void) => {
  const tx = client.multi();
  await chain(tx);
  return tx.exec();
};

```

### List-Based Caching

The `setKeyWithList` function stores values with automatic list indexing:

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
const setKeyWithList = async (keyId, listIds, keyData, expirationTime) => {
  const keyPromise = getClientBase().set(keyId, JSON.stringify(keyData), 'EX', expirationTime);
  const listsPromise = listIds.map((listId) => setInList(listId, keyId, expirationTime));
  await Promise.all([keyPromise, ...listsPromise]);
  return keyData;
};

```

### Common Cache Types

| Cache | Helper Functions | Use Case |
|-------|----------------|----------|
| **Session** (`platform_sessions`) | `setSession`, `getSession`, `extendSession` | JWT token storage |
| **Edit Context** (`edit:{instanceId}:{userId}`) | `setEditContext`, `fetchEditContext`, `delEditContext` | Collaborative UI editing |
| **Work Progress** (`work:{connectorId}`) | `redisInitializeWork`, `redisUpdateWorkFigures`, `redisGetWork` | Connector import tracking |
| **Telemetry** (`telemetry_events`) | `redisSetTelemetryAdd`, `redisGetTelemetry` | Platform metrics |

All cache operations use `getClientBase()` or `getClientLock()` for distributed locking.

## Configuring Pub/Sub for Real-Time Updates

OpenCTI uses Redis pub/sub to power GraphQL subscriptions for live UI updates. The implementation wraps `graphql-redis-subscriptions` around dedicated publisher and subscriber clients.

### Publishing Events

The `notify` function in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts) publishes changes to subscribers:

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const notify = async (topic: string, instance: any, user: AuthUser) => {
  if (isNotEmptyField(instance)) {
    const data = Array.isArray(instance)
      ? instance.map((i) => R.dissoc(INPUT_OBJECTS, i))
      : R.dissoc(INPUT_OBJECTS, instance);
    await refreshLocalCacheForEntity(topic, data as unknown as BasicStoreCommon);
    await getClientPubSub().publish(topic, { instance: data, user });
  }
  return instance;
};

```

The payload includes the instance data (with heavy input objects removed) and the user who performed the action. The function first refreshes the local cache, then publishes to ensure subscribers receive consistent data.

### Subscribing in GraphQL Resolvers

Use `pubSubAsyncIterator` to create subscription resolvers:

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis.ts
export const pubSubAsyncIterator = (topic: string | string[]) => {
  return getClientPubSub().asyncIterator(topic);
};

export const pubSubSubscription = async <T>(topic: string, onMessage: (message: T) => void) => {
  const subscription = await getClientPubSub().subscribe(topic, onMessage, { pattern: true });
  const unsubscribe = () => getClientPubSub().unsubscribe(subscription);
  return { topic, unsubscribe };
};

```

Example GraphQL resolver implementation:

```typescript
const resolvers = {
  Subscription: {
    liveUpdates: {
      subscribe: (_, __, { user }) => {
        const topic = `live:${user.id}`;
        return pubSubAsyncIterator(topic);
      },
    },
  },
};

```

OpenCTI uses topic patterns like `live:${userId}` and `connector-${id}-logs` to route events to specific clients.

## Redis Stream Trimming Configuration

OpenCTI stores UI activity history in a Redis Stream managed by [`opencti-graphql/src/database/redis-stream.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis-stream.ts). To prevent unbounded memory growth, the platform automatically trims streams based on the `REDIS__TRIMMING` configuration.

```typescript
// https://github.com/OpenCTI-Platform/opencti/blob/master/opencti-graphql/src/database/redis-stream.ts
const streamTrimming = conf.get('redis:trimming') || 0;

```

The default value of `2000000` entries (approximately 8GB) balances history retention with memory usage. Adjust `REDIS__TRIMMING` based on your infrastructure capacity and audit requirements.

## Complete Configuration Example

### Docker Compose Setup

```yaml

# docker-compose.yml

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis_data:/data
volumes:
  redis_data:

```

### Environment Configuration

```dotenv

# .env

REDIS__MODE=single
REDIS__HOSTNAME=redis
REDIS__PORT=6379
REDIS__USE_SSL=false
REDIS__NAMESPACE=opencti
REDIS__TRIMMING=2000000

```

### Sentinel Configuration

For high availability, use Redis Sentinel:

```dotenv
REDIS__MODE=sentinel
REDIS__HOSTNAMES=["sentinel1:26379","sentinel2:26379","sentinel3:26379"]
REDIS__SENTINEL_MASTER_NAME=mymaster
REDIS__PASSWORD=your_redis_password

```

## Summary

- **Configuration**: Set `REDIS__MODE` to `single`, `sentinel`, or `cluster` and provide appropriate host and authentication details via environment variables.
- **Client Initialization**: The platform creates four dedicated Redis connections (`base`, `xrange`, `lock`, `pubsub`) through `initializeRedisClients()` in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts).
- **Caching**: Use `getClientBase()` with helpers like `setKeyWithList` and `redisTx` to store sessions, edit contexts, and work progress with TTL support.
- **Pub/Sub**: Real-time updates flow through `graphql-redis-subscriptions` using `notify()` to publish and `pubSubAsyncIterator()` to subscribe in GraphQL resolvers.
- **Stream Management**: Configure `REDIS__TRIMMING` to limit UI history stream size in [`opencti-graphql/src/database/redis-stream.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis-stream.ts).

## Frequently Asked Questions

### What is the difference between the base Redis client and the pub/sub client in OpenCTI?

The **base client** (`getClientBase()`) handles standard caching operations like `GET`, `SET`, and `ZADD` for sessions, edit contexts, and work progress. The **pub/sub client** (`getClientPubSub()`) is a specialized connection created by `graphql-redis-subscriptions` that handles `PUBLISH` and `SUBSCRIBE` commands for real-time GraphQL updates. OpenCTI initializes separate physical connections for each role to prevent command interference and enable independent scaling.

### How do I enable TLS for Redis connections in OpenCTI?

Set `REDIS__USE_SSL=true` and provide CA certificate paths via `REDIS__CA` as a JSON array of file paths. The `createRedisClient` factory in [`opencti-graphql/src/database/redis.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-graphql/src/database/redis.ts) automatically injects TLS options into the Redis connection configuration when `USE_SSL` is enabled, including the `servername` parameter for SNI validation.

### What happens if Redis becomes unavailable during OpenCTI runtime?

OpenCTI uses `ioredis` with `enableOfflineQueue: true` and `lazyConnect: true`, allowing the application to start even if Redis is temporarily unavailable. The `retryStrategy` in `redisOptions` attempts reconnection with exponential backoff up to 2000ms for clients initialized with `autoReconnect = true`. However, real-time pub/sub functionality will stall until connectivity resumes, and caching operations will queue or fail depending on the specific client configuration.

### How do I configure Redis Sentinel for high availability in OpenCTI?

Set `REDIS__MODE=sentinel` and provide the sentinel host array via `REDIS__HOSTNAMES` as a JSON string like `["sentinel1:26379","sentinel2:26379"]`. You must also specify `REDIS__SENTINEL_MASTER_NAME` to identify the Redis master instance. The `createRedisClient` factory automatically constructs sentinel-specific connection options and handles failover detection through the `ioredis` sentinel implementation.