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,          // ioredis only
    enableOfflineQueue: true,
    enableAutoReconnect: true,
    maxRetriesPerRequest: 3,   // ioredis only
  },
})

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 ​

12-factor platforms (Heroku, Railway, Upstash, docker-compose, .env) expose a single REDIS_URL. Pass it directly as url — no manual parsing:

typescript
RedisModule.forRoot({
  clients: { url: process.env.REDIS_URL }, // redis://user:pass@host:6379/0
})

rediss:// enables TLS, and a database number in the path (…/2) selects the DB. Any field also set explicitly overrides the value parsed from the URL:

typescript
RedisModule.forRoot({
  clients: {
    url: 'rediss://:secret@cache.upstash.io:6379/0',
    keyPrefix: 'myapp:',      // merged on top of the URL
    tls: { rejectUnauthorized: false }, // merged over the rediss:// TLS
  },
})

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,   // ioredis only
    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,   // ioredis only
    tls: {
      enabled: true,
      rejectUnauthorized: true,
    },
    sentinelOptions: {
      sentinelPassword: 'sentinel-password',
      enableTLSForSentinelMode: true,
      sentinelRetryStrategy: (times) => Math.min(times * 50, 2000),
      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,
    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 the sentinel hops (requires the tls block — it supplies the certificates; data-node TLS follows tls.enabled regardless)
sentinelRetryStrategy-Custom retry strategy for sentinel reconnection (ioredis only — node-redis rotates to the next sentinel instead)

ioredis-Specific Options ​

OptionDefaultDescription
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',
  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.