npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@synet/kv-redis

v1.0.2

Published

Redis adapter for KeyValue Unit

Readme

@synet/kv-redis

  _____          _ _                     
 |  __ \        | (_)                    
 | |__) |___  __| |_ ___                 
 |  _  // _ \/ _` | / __|                
 | | \ \  __/ (_| | \__ \                
 |_|  \_\___|\__,_|_|___/   _            
     /\      | |           | |           
    /  \   __| | __ _ _ __ | |_ ___ _ __ 
   / /\ \ / _` |/ _` | '_ \| __/ _ \ '__|
  / ____ \ (_| | (_| | |_) | ||  __/ |   
 /_/    \_\__,_|\__,_| .__/ \__\___|_|   
                     | |                 
                     |_|                 
version: 1.0.2

Production-ready Redis adapter for @synet/kv with advanced features

High-performance Redis adapter for @synet/kv that provides distributed key-value storage with Redis-native optimizations, pipeline operations, and comprehensive monitoring.

Features

  • Redis Pipelines - Efficient batch operations using Redis pipelines
  • Connection Management - Robust connection handling with auto-retry
  • Native TTL - Uses Redis native expiration for optimal performance
  • Health Monitoring - Comprehensive statistics and health checks
  • Auto-Reconnection - Automatic reconnection with configurable retry logic
  • Memory Optimization - Smart memory usage tracking and management
  • Type Safety - Full TypeScript support with generic preservation
  • Unit Architecture - Compatible with SYNET Unit Architecture patterns

Installation

npm install @synet/kv-redis ioredis

Quick Start

import { KeyValue } from '@synet/kv';
import { RedisAdapter } from '@synet/kv-redis';

// Create Redis adapter
const adapter = new RedisAdapter({
  host: 'localhost',
  port: 6379,
  keyPrefix: 'myapp:',
  defaultTTL: 3600000, // 1 hour
  connectionTimeout: 10000,
  maxRetriesPerRequest: 3
});

// Create KV instance
const kv = KeyValue.create({ adapter });

// Use same API as memory adapter
await kv.set('user:123', { name: 'Alice', email: '[email protected]' });
const user = await kv.get('user:123');
console.log(user); // { name: 'Alice', email: '[email protected]' }

Configuration

RedisAdapterConfig

interface RedisAdapterConfig {
  // Connection Settings
  host?: string;                    // Redis host (default: 'localhost')
  port?: number;                    // Redis port (default: 6379)
  url?: string;                     // Redis URL (overrides host/port)
  password?: string;                // Redis password
  username?: string;                // Redis username (Redis 6+)
  db?: number;                      // Redis database number (default: 0)
  
  // Key Management
  keyPrefix?: string;               // Prefix for all keys (default: '')
  defaultTTL?: number;              // Default TTL in milliseconds
  
  // Connection Options
  connectionTimeout?: number;       // Connection timeout (default: 10000ms)
  commandTimeout?: number;          // Command timeout (default: 5000ms)
  maxRetriesPerRequest?: number;    // Max retries per request (default: 3)
  enableReadyCheck?: boolean;       // Enable ready check (default: false)
  
  // Advanced
  redisInstance?: Redis;            // Use existing Redis instance
  serialization?: SerializationAdapter; // Custom serialization
}

Connection Examples

// Basic connection
const adapter = new RedisAdapter({
  host: 'localhost',
  port: 6379
});

// URL-based connection
const adapter = new RedisAdapter({
  url: 'redis://username:password@localhost:6379/0'
});

// Production configuration
const adapter = new RedisAdapter({
  host: process.env.REDIS_HOST,
  port: parseInt(process.env.REDIS_PORT || '6379'),
  password: process.env.REDIS_PASSWORD,
  keyPrefix: process.env.APP_NAME + ':',
  defaultTTL: 3600000, // 1 hour
  connectionTimeout: 15000,
  commandTimeout: 8000,
  maxRetriesPerRequest: 5
});

// Cluster configuration
const adapter = new RedisAdapter({
  url: 'redis://cluster-endpoint:6379',
  enableReadyCheck: false,
  maxRetriesPerRequest: 3
});

Advanced Usage

Pipeline Operations

The Redis adapter automatically uses pipelines for batch operations to maximize performance:

// Batch set - uses Redis pipeline internally
const entries: Array<[string, any]> = [
  ['user:1', { name: 'Alice' }],
  ['user:2', { name: 'Bob' }],
  ['user:3', { name: 'Charlie' }]
];

await kv.mset(entries, 1800000); // 30 minutes TTL

// Batch get - uses Redis MGET
const keys = ['user:1', 'user:2', 'user:3'];
const users = await kv.mget(keys);

// Large batch delete - automatically chunked with pipelines
const manyKeys = Array.from({ length: 1000 }, (_, i) => `temp:${i}`);
await kv.deleteMany(manyKeys);

Health Monitoring

// Basic health check
const isHealthy = await adapter.isHealthy();
console.log('Redis healthy:', isHealthy);

// Detailed health status
const health = await adapter.getHealthStatus();
console.log('Health Status:', {
  healthy: health.healthy,
  connected: health.connected,
  latency: health.latency + 'ms',
  lastCheck: health.lastCheck,
  error: health.error // if any
});

// Comprehensive statistics
const stats = await adapter.getStatistics();
console.log('Redis Statistics:', {
  connected: stats.connected,
  commands: stats.commands,
  operations: stats.operations,
  memory: stats.memory,
  connection: stats.connection
});

Connection Management

// Wait for Redis to be ready
await adapter.waitUntilReady(10000); // 10 second timeout

// Get connection information
const info = adapter.getConnectionInfo();
console.log('Connection:', {
  host: info.host,
  port: info.port,
  database: info.db,
  status: info.status
});

// Test connection
const pingResponse = await adapter.ping();
console.log('Ping:', pingResponse); // 'PONG'

// Access underlying Redis instance for advanced operations
const redis = adapter.getRedis();
await redis.eval('return redis.call("GET", KEYS[1])', 1, 'mykey');

TTL Management

// Set with TTL (Redis native expiration)
await kv.set('session:abc123', sessionData, 1800000); // 30 minutes

// Set with default TTL (configured in adapter)
await kv.set('cache:popular-posts', posts); // Uses defaultTTL

// Check if key exists (respects TTL)
const exists = await kv.exists('session:abc123');

// TTL is handled natively by Redis for optimal performance

Error Handling

try {
  await kv.set('mykey', 'myvalue');
} catch (error) {
  if (error.message.includes('[RedisAdapter]')) {
    // Handle Redis-specific errors
    console.error('Redis operation failed:', error.message);
    
    // Check if adapter is still healthy
    const healthy = await adapter.isHealthy();
    if (!healthy) {
      // Implement fallback or retry logic
    }
  }
}

Production Deployment

Docker Setup

# Dockerfile
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

EXPOSE 3000
CMD ["node", "dist/index.js"]
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    environment:
      NODE_ENV: production
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      APP_NAME: myapp
    depends_on:
      - redis
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: unless-stopped

volumes:
  redis_data:

Environment Configuration

// config/redis.ts
import { RedisAdapter } from '@synet/kv-redis';

export function createRedisAdapter() {
  return new RedisAdapter({
    host: process.env.REDIS_HOST || 'localhost',
    port: parseInt(process.env.REDIS_PORT || '6379'),
    password: process.env.REDIS_PASSWORD,
    keyPrefix: (process.env.APP_NAME || 'app') + ':',
    defaultTTL: parseInt(process.env.DEFAULT_TTL || '3600000'), // 1 hour
    connectionTimeout: 15000,
    commandTimeout: 8000,
    maxRetriesPerRequest: 5
  });
}

High Availability Setup

// For Redis Cluster
const adapter = new RedisAdapter({
  url: process.env.REDIS_CLUSTER_URL,
  enableReadyCheck: false,
  maxRetriesPerRequest: 3,
  connectionTimeout: 20000
});

// For Redis Sentinel
const adapter = new RedisAdapter({
  // Configure for Sentinel setup
  host: process.env.REDIS_SENTINEL_HOST,
  port: parseInt(process.env.REDIS_SENTINEL_PORT || '26379'),
  maxRetriesPerRequest: 5
});

Performance Optimization

Batch Operations

// Efficient bulk operations
const BATCH_SIZE = 100;

async function processBulkData(items: any[]) {
  for (let i = 0; i < items.length; i += BATCH_SIZE) {
    const batch = items.slice(i, i + BATCH_SIZE);
    const entries = batch.map((item, idx) => [
      `item:${i + idx}`,
      item
    ] as [string, any]);
    
    // Single pipeline operation for the batch
    await kv.mset(entries, 3600000); // 1 hour TTL
  }
}

Memory Management

// Monitor Redis memory usage
async function monitorMemory() {
  const stats = await adapter.getStatistics();
  
  if (stats.memory) {
    const usedMB = stats.memory.used / 1024 / 1024;
    const peakMB = stats.memory.peak / 1024 / 1024;
    
    console.log(`Redis Memory: ${usedMB.toFixed(2)}MB (Peak: ${peakMB.toFixed(2)}MB)`);
    
    // Alert if memory usage is too high
    if (usedMB > 1000) { // 1GB threshold
      console.warn('Redis memory usage is high!');
    }
  }
}

// Run monitoring every 5 minutes
setInterval(monitorMemory, 5 * 60 * 1000);

Testing

# Run tests (requires Redis on port 6379)
npm test

# Run demo
npm run demo

# Run with coverage
npm run coverage

Test with Docker

# Start Redis for testing
docker run -d --name redis-test -p 6379:6379 redis:7-alpine

# Run tests
npm test

# Cleanup
docker stop redis-test && docker rm redis-test

🔧 Troubleshooting

Common Issues

Connection Timeouts

// Increase timeout for slow networks
const adapter = new RedisAdapter({
  connectionTimeout: 30000, // 30 seconds
  commandTimeout: 15000     // 15 seconds
});

Memory Issues

// Use shorter TTL for cache data
await kv.set('cache:data', data, 300000); // 5 minutes instead of 1 hour

// Monitor memory usage
const stats = await adapter.getStatistics();
console.log('Memory usage:', stats.memory);

Performance Issues

// Use batch operations for multiple keys
await kv.mset(entries); // Instead of multiple set() calls

// Use appropriate key prefixes
const adapter = new RedisAdapter({
  keyPrefix: 'myapp:cache:' // Clear namespace
});

Monitoring & Metrics

Custom Monitoring

class RedisMonitor {
  constructor(private adapter: RedisAdapter) {}

  async getMetrics() {
    const stats = await this.adapter.getStatistics();
    const health = await this.adapter.getHealthStatus();
    
    return {
      // Connection metrics
      connected: stats.connected,
      latency: health.latency,
      
      // Command metrics
      totalCommands: stats.commands.total,
      failedCommands: stats.commands.failed,
      successRate: stats.commands.successful / stats.commands.total,
      
      // Operation metrics
      operations: stats.operations,
      
      // Memory metrics
      memoryUsed: stats.memory?.used || 0,
      memoryPeak: stats.memory?.peak || 0
    };
  }

  async logMetrics() {
    const metrics = await this.getMetrics();
    console.log('Redis Metrics:', JSON.stringify(metrics, null, 2));
  }
}

const monitor = new RedisMonitor(adapter);
setInterval(() => monitor.logMetrics(), 60000); // Every minute

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

MIT License - see LICENSE file for details.

🔗 Related Packages

  • @synet/kv - Core key-value storage with Unit Architecture
  • @synet/unit - SYNET Unit Architecture framework

Made with ❤️ by the SYNET Team