Skip to content

Connection Types

Configure Redis for different deployment topologies.

Overview

TypeUse CaseHigh AvailabilityScaling
SingleDevelopment, small appsNoVertical only
ClusterLarge scale, shardingYesHorizontal
SentinelHA without shardingYesVertical

Single Instance

Standard Redis connection for development and small-scale deployments.

Basic Configuration

typescript
RedisModule.forRoot({
  clients: {
    host: 'localhost',
    port: 6379,
  },
})

Full Configuration

typescript
RedisModule.forRoot({
  clients: {
    type: 'single',  // Optional, default
    host: 'redis.example.com',
    port: 6379,
    password: 'secret',
    db: 0,
    keyPrefix: 'myapp:',
    connectTimeout: 10000,
    commandTimeout: 5000,
    keepAlive: 30000,
    enableOfflineQueue: true,
    enableAutoReconnect: true,
    maxRetriesPerRequest: 3,
  },
})

With TLS

typescript
RedisModule.forRoot({
  clients: {
    host: 'redis.example.com',
    port: 6380,
    tls: {
      enabled: true,
      rejectUnauthorized: true,
      ca: fs.readFileSync('/path/to/ca.crt'),
      cert: fs.readFileSync('/path/to/client.crt'),
      key: fs.readFileSync('/path/to/client.key'),
    },
  },
})

Connection URL

For cloud services that provide connection URLs:

typescript
// Parse URL manually or use environment variables
const redisUrl = new URL(process.env.REDIS_URL);

RedisModule.forRoot({
  clients: {
    host: redisUrl.hostname,
    port: parseInt(redisUrl.port),
    password: redisUrl.password,
    tls: redisUrl.protocol === 'rediss:' ? { enabled: true } : undefined,
  },
})

Redis Cluster

Distributed Redis for horizontal scaling and high availability.

Basic Configuration

typescript
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [
      { host: 'redis-1', port: 6379 },
      { host: 'redis-2', port: 6379 },
      { host: 'redis-3', port: 6379 },
    ],
  },
})

Full Configuration

typescript
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [
      { host: 'redis-1', port: 6379 },
      { host: 'redis-2', port: 6379 },
      { host: 'redis-3', port: 6379 },
      { host: 'redis-4', port: 6379 },
      { host: 'redis-5', port: 6379 },
      { host: 'redis-6', port: 6379 },
    ],
    password: 'secret',
    db: 0,
    keyPrefix: 'myapp:',
    connectTimeout: 10000,
    commandTimeout: 5000,
    maxRetriesPerRequest: 3,
    retryStrategy: (times) => Math.min(times * 50, 2000),
    clusterOptions: {
      maxRedirections: 16,
      retryDelayOnClusterDown: 100,
      retryDelayOnFailover: 100,
      scaleReads: 'slave',
      enableReadyCheck: true,
      natMap: {
        '172.17.0.2:6379': { host: 'localhost', port: 7000 },
      },
    },
  },
})

Cluster Options

OptionDefaultDescription
maxRedirections16Maximum MOVED/ASK redirections
retryDelayOnClusterDown100Delay (ms) when cluster is down
retryDelayOnFailover100Delay (ms) during failover
scaleReads'master'Read from: 'master', 'slave', 'all'
enableReadyCheckfalseWait for cluster ready
natMap-NAT mapping for Docker/firewall scenarios

Scale Reads

typescript
// Read from master only (default)
clusterOptions: {
  scaleReads: 'master',
}

// Read from slaves (replicas)
clusterOptions: {
  scaleReads: 'slave',
}

// Read from any node
clusterOptions: {
  scaleReads: 'all',
}

NAT Mapping (Docker/Kubernetes)

When cluster nodes report internal IPs that aren't accessible, use natMap to map internal addresses to external ones. This works with both drivers — ioredis uses natMap natively, node-redis translates it to nodeAddressMap automatically:

typescript
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [
      { host: 'localhost', port: 7000 },
      { host: 'localhost', port: 7001 },
      { host: 'localhost', port: 7002 },
    ],
    clusterOptions: {
      natMap: {
        '172.17.0.2:6379': { host: 'localhost', port: 7000 },
        '172.17.0.3:6379': { host: 'localhost', port: 7001 },
        '172.17.0.4:6379': { host: 'localhost', port: 7002 },
      },
    },
  },
})

Cluster Commands

typescript
import { Injectable } from '@nestjs/common';
import { RedisService } from '@nestjs-redisx/core';

@Injectable()
export class ClusterService {
  constructor(private readonly redis: RedisService) {}

  async getClusterInfo(): Promise<string> {
    const client = await this.redis.getClient();
    return client.cluster('INFO') as Promise<string>;
  }

  async getClusterNodes(): Promise<string> {
    const client = await this.redis.getClient();
    return client.cluster('NODES') as Promise<string>;
  }

  async getClusterSlots(): Promise<unknown> {
    const client = await this.redis.getClient();
    return client.cluster('SLOTS');
  }
}

Redis Sentinel

High availability with automatic failover (without sharding).

Basic Configuration

typescript
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [
      { host: 'sentinel-1', port: 26379 },
      { host: 'sentinel-2', port: 26379 },
      { host: 'sentinel-3', port: 26379 },
    ],
    name: 'mymaster',
  },
})

Full Configuration

typescript
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [
      { host: 'sentinel-1', port: 26379 },
      { host: 'sentinel-2', port: 26379 },
      { host: 'sentinel-3', port: 26379 },
    ],
    name: 'mymaster',
    password: 'redis-password',
    db: 0,
    keyPrefix: 'myapp:',
    connectTimeout: 10000,
    commandTimeout: 5000,
    maxRetriesPerRequest: 3,
    tls: {
      enabled: true,
      rejectUnauthorized: true,
    },
    sentinelOptions: {
      sentinelPassword: 'sentinel-password',
      enableTLSForSentinelMode: true,
      sentinelRetryStrategy: (times) => Math.min(times * 50, 2000),
      preferredSlaves: false,          // ioredis only
      natMap: {                        // ioredis only
        'redis-master:6379': { host: 'localhost', port: 6379 },
      },
    },
  },
})
typescript
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [
      { host: 'sentinel-1', port: 26379 },
      { host: 'sentinel-2', port: 26379 },
      { host: 'sentinel-3', port: 26379 },
    ],
    name: 'mymaster',
    password: 'redis-password',
    db: 0,
    keyPrefix: 'myapp:',
    connectTimeout: 10000,
    commandTimeout: 5000,
    maxRetriesPerRequest: 3,
    tls: {
      enabled: true,
      rejectUnauthorized: true,
    },
    sentinelOptions: {
      sentinelPassword: 'sentinel-password',
      enableTLSForSentinelMode: true,
      sentinelRetryStrategy: (times) => Math.min(times * 50, 2000),
      masterPoolSize: 1,               // node-redis only
      replicaPoolSize: 0,              // node-redis only
      scanInterval: 10000,             // node-redis only
      maxCommandRediscovers: 16,       // node-redis only
    },
  },
})

Sentinel Options

Options inside sentinelOptions vary by driver. Common options work with both:

Common Options

OptionDefaultDescription
sentinelPassword-Password for Sentinel authentication
enableTLSForSentinelModefalseUse TLS for Sentinel connections
sentinelRetryStrategy-Custom retry strategy for sentinel reconnection

ioredis-Specific Options

OptionDefaultDescription
preferredSlavesfalsePrefer slave nodes for reads
natMap-NAT mapping for Docker/firewall scenarios

node-redis-Specific Options

OptionDefaultDescription
masterPoolSize1Number of connections to master
replicaPoolSize0Number of connections per replica (0 = disabled)
scanInterval10000Topology scan interval (ms)
maxCommandRediscovers16Max rediscovers on topology change

Example: driver-specific sentinel options

typescript
sentinelOptions: {
  sentinelPassword: 'secret',
  preferredSlaves: false,
  natMap: {
    'redis-master:6379': { host: 'localhost', port: 6379 },
  },
}
typescript
sentinelOptions: {
  sentinelPassword: 'secret',
  masterPoolSize: 2,
  replicaPoolSize: 1,
  scanInterval: 5000,
}

TLS for Sentinel

Use the top-level tls config for node connections. Use sentinelOptions.enableTLSForSentinelMode to also apply TLS to sentinel connections. Both drivers support this.

NAT Mapping for Sentinel

ioredis Only

NAT mapping for Sentinel is only supported with the ioredis driver. The node-redis sentinel adapter (createSentinel()) does not support natMap.

typescript
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [
      { host: 'localhost', port: 26379 },
    ],
    name: 'mymaster',
    sentinelOptions: {
      natMap: {
        'redis-master:6379': { host: 'localhost', port: 6379 },
        'redis-slave-1:6379': { host: 'localhost', port: 6380 },
        'redis-slave-2:6379': { host: 'localhost', port: 6381 },
      },
    },
  },
})

Sentinel Commands

typescript
import { Injectable } from '@nestjs/common';
import { RedisService } from '@nestjs-redisx/core';

@Injectable()
export class SentinelService {
  constructor(private readonly redis: RedisService) {}

  async getMasters(): Promise<unknown> {
    const client = await this.redis.getClient();
    return client.sentinel('MASTERS');
  }

  async getMaster(name: string): Promise<unknown> {
    const client = await this.redis.getClient();
    return client.sentinel('MASTER', name);
  }

  async getReplicas(masterName: string): Promise<unknown> {
    const client = await this.redis.getClient();
    return client.sentinel('REPLICAS', masterName);
  }
}

Connection Comparison

Choosing Connection Type

Use Single Instance When

  • Development environment
  • Small applications with low traffic
  • Data fits in single instance memory
  • No HA requirements

Use Cluster When

  • Large datasets requiring sharding
  • High throughput requirements
  • Horizontal scaling needed
  • Multi-key operations are limited

Use Sentinel When

  • High availability required
  • Data fits in single instance
  • Automatic failover needed
  • No sharding requirements

Environment-Based Type Selection

typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisModule } from '@nestjs-redisx/core';

@Module({
  imports: [
    ConfigModule.forRoot(),
    RedisModule.forRootAsync({
      useFactory: (config: ConfigService) => {
        const env = config.get('NODE_ENV');

        if (env === 'production') {
          return {
            clients: {
              type: 'cluster' as const,
              nodes: JSON.parse(config.get<string>('REDIS_CLUSTER_NODES', '[]')),
              password: config.get<string>('REDIS_PASSWORD'),
            },
          };
        }

        return {
          clients: {
            host: config.get<string>('REDIS_HOST', 'localhost'),
            port: config.get<number>('REDIS_PORT', 6379),
          },
        };
      },
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Next Steps

Released under the MIT License.