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

@memberjunction/redis-provider

v5.11.0

Published

Redis-backed ILocalStorageProvider for MemberJunction — enables shared, persistent server-side caching via any Redis-compatible service (Azure Managed Redis, AWS ElastiCache, self-hosted, etc.)

Readme

@memberjunction/redis-provider

Redis-backed implementation of MemberJunction's ILocalStorageProvider interface. Enables persistent, shared server-side caching via any Redis-compatible service — self-hosted Redis, Azure Managed Redis, AWS ElastiCache, Redis Cloud, Upstash, or any other Redis-protocol endpoint.

Why Redis?

MemberJunction's default server-side cache (InMemoryLocalStorageProvider) stores data in a plain Map inside the Node.js process. This works well for single-server development but has two limitations in production:

| Limitation | Impact | |-----------|--------| | Not shared | Each MJAPI instance has its own cache — no benefit from horizontal scaling | | Not persistent | Cache is lost on process restart — cold starts hit the database for everything |

A Redis-backed provider solves both problems while remaining a drop-in replacement — no changes to LocalCacheManager, ProviderBase, or any consumer code.

Installation

# Add to the package that configures your data provider (typically MJAPI or your server bootstrap)
# Then run npm install at the repo root
npm install @memberjunction/redis-provider

Monorepo note: In the MemberJunction monorepo, add the dependency to the relevant package's package.json and run npm install at the repo root.

Quick Start

import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';
import { Metadata } from '@memberjunction/core';
import type { GenericDatabaseProvider } from '@memberjunction/generic-database-provider';

// 1. Create the Redis provider
const redisProvider = new RedisLocalStorageProvider({
    url: 'redis://localhost:6379',
    defaultTTLSeconds: 300,  // 5-minute default TTL
});

// 2. Inject it into the data provider
const provider = Metadata.Provider as GenericDatabaseProvider;
provider.SetLocalStorageProvider(redisProvider);

// That's it! All MJ caching now flows through Redis.

Configuration

The RedisProviderConfig object supports the following options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | url | string | — | Redis connection URL (redis:// or rediss:// for TLS). Mutually exclusive with options. | | options | RedisOptions | — | Full ioredis options object. Mutually exclusive with url. | | keyPrefix | string | 'mj' | Prefix for all Redis keys. Useful for isolating MJ data in a shared Redis instance. | | defaultTTLSeconds | number | undefined | Default time-to-live for all cached entries. undefined means keys persist until explicitly removed. | | maxRetries | number | 10 | Maximum reconnection attempts with exponential backoff before giving up. | | enableLogging | boolean | true | Whether to log connection events via MJ's LogStatus/LogError. |

Connection Examples

Local Development (Docker)

# Start a local Redis container
docker run -d --name mj-redis -p 6379:6379 redis:7-alpine
const provider = new RedisLocalStorageProvider({
    url: 'redis://localhost:6379',
    defaultTTLSeconds: 300,
});

Azure Managed Redis

const provider = new RedisLocalStorageProvider({
    url: `rediss://default:${process.env.AZURE_REDIS_KEY}@${process.env.AZURE_REDIS_HOST}:6380`,
    defaultTTLSeconds: 600,
});

Or using the options object for more control:

const provider = new RedisLocalStorageProvider({
    options: {
        host: process.env.AZURE_REDIS_HOST,
        port: 6380,
        password: process.env.AZURE_REDIS_KEY,
        tls: {},  // Required for Azure
        db: 0,
    },
    defaultTTLSeconds: 600,
});

AWS ElastiCache

const provider = new RedisLocalStorageProvider({
    options: {
        host: 'my-cluster.abc123.use1.cache.amazonaws.com',
        port: 6379,
        tls: {},  // Required for encryption in transit
    },
    defaultTTLSeconds: 600,
});

Redis Cloud / Upstash

const provider = new RedisLocalStorageProvider({
    url: process.env.REDIS_URL,  // Provided by the service
    defaultTTLSeconds: 600,
});

Architecture

How It Fits Into MemberJunction

┌─────────────────────────────────────────────────────────────┐
│                    Application Layer                        │
│  (MJAPI, Angular, React, Custom Apps)                       │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
              ┌──────────────────────┐
              │  LocalCacheManager   │   Singleton — LRU eviction, TTL,
              │  (MJCore)            │   stats, category-based isolation
              └──────────┬───────────┘
                         │
                         ▼
              ┌──────────────────────┐
              │  ILocalStorageProvider│   Abstract interface (MJCore)
              └──────────┬───────────┘
                         │
            ┌────────────┼────────────────┐
            │            │                │
            ▼            ▼                ▼
    ┌──────────────┐ ┌──────────┐ ┌────────────────┐
    │ InMemory     │ │ Browser  │ │ Redis          │
    │ (default)    │ │ (IDB/LS) │ │ (this package) │
    └──────────────┘ └──────────┘ └────────┬───────┘
                                           │
                                           ▼
                                    ┌─────────────┐
                                    │ Redis Server │
                                    │ (any host)   │
                                    └─────────────┘

Key Structure

All keys follow the pattern: {prefix}:{category}:{key}

  • prefix — Configurable (default "mj"), isolates MJ data in shared Redis instances
  • category — Maps to MJ cache categories: RunViewCache, Metadata, DatasetCache, RunQueryCache, default
  • key — The original key from the calling code

Example Redis keys:

mj:RunViewCache:Users|Active=1|Name ASC
mj:Metadata:___MJCore_Metadata_AllMetadata
mj:DatasetCache:MyDataset_items
mj:default:some-arbitrary-key

Category Tracking

Each category has an associated Redis Set at {prefix}:__categories__:{category} that tracks all member keys. This enables efficient:

  • ClearCategory() — Deletes all keys in a category in a single pipeline
  • GetCategoryKeys() — Lists all keys without scanning the entire keyspace

TTL (Time-to-Live)

Redis has native key expiration, so TTL is handled efficiently at the server level:

  1. Config defaultdefaultTTLSeconds applies to every SetItem() call
  2. Per-call overrideSetItem(key, value, category, ttlSeconds) overrides the default
  3. No TTL — If neither is set, keys persist until explicitly removed or ClearCategory() is called

Error Handling

All Redis operations are wrapped in try/catch. On failure:

  • Reads return null (cache miss, falls through to database)
  • Writes are silently skipped (data stays in the database, just not cached)
  • Connection errors are logged via LogError() but don't crash the app
  • Reconnection is automatic via ioredis with configurable exponential backoff

This design ensures a Redis outage degrades performance (more database hits) but never causes application downtime.

API Reference

RedisLocalStorageProvider

Constructor

new RedisLocalStorageProvider(config?: RedisProviderConfig)

Creates a new provider and establishes a Redis connection. The connection is lazy — it happens on the first command, so construction itself does not block.

ILocalStorageProvider Methods

| Method | Description | |--------|-------------| | GetItem(key, category?) | Retrieves a cached value. Returns null on miss or error. | | SetItem(key, value, category?, ttlSeconds?) | Stores a value with optional TTL. Uses pipeline for atomic set + category tracking. | | Remove(key, category?) | Deletes a key and removes it from category tracking. | | ClearCategory(category) | Deletes all keys in a category using the tracking Set. | | GetCategoryKeys(category) | Returns all key names in a category. |

Additional Methods

| Method | Description | |--------|-------------| | Exists(key, category?) | Checks key existence without transferring the value (more efficient than GetItem). | | GetTTL(key, category?) | Returns remaining TTL in seconds (-1 = no expiry, -2 = key doesn't exist). | | Ping() | Health check — returns true if Redis responds with PONG. | | Disconnect() | Graceful shutdown — sends QUIT and waits for pending replies. |

Properties

| Property | Type | Description | |----------|------|-------------| | IsConnected | boolean | Whether the client has an active connection (transient — auto-reconnects). | | Client | Redis | The underlying ioredis client for advanced operations (pub/sub, streams, etc.). |

Testing

Unit Tests (No Redis Required)

The package includes comprehensive unit tests with mocked Redis:

cd packages/RedisProvider
npm run test

Integration Testing with Local Redis

For end-to-end testing with a real Redis instance:

# Start Redis
docker run -d --name mj-redis -p 6379:6379 redis:7-alpine

# Verify connectivity
docker exec mj-redis redis-cli ping
# → PONG

# Run your MJAPI with Redis configured
REDIS_URL=redis://localhost:6379 npm run start:api

# Monitor Redis activity in real time
docker exec mj-redis redis-cli monitor

# Clean up
docker stop mj-redis && docker rm mj-redis

Monitoring Redis Usage

# See all MJ keys
docker exec mj-redis redis-cli KEYS "mj:*"

# Check memory usage
docker exec mj-redis redis-cli INFO memory

# See cache hit/miss stats
docker exec mj-redis redis-cli INFO stats | grep keyspace

Production Recommendations

TTL Strategy

| Category | Recommended TTL | Rationale | |----------|----------------|-----------| | Metadata | 30–60 minutes | Entity schema changes infrequently | | RunViewCache | 2–5 minutes | Balance freshness vs. database load | | RunQueryCache | 2–5 minutes | Same as RunViewCache | | DatasetCache | 5–10 minutes | Datasets are typically larger, change less often |

Memory Management

  • Set maxmemory and maxmemory-policy allkeys-lru in your Redis configuration so Redis automatically evicts least-recently-used keys when memory is full
  • Monitor with INFO memory and set alerts on used_memory_peak
  • Use defaultTTLSeconds to ensure keys don't accumulate indefinitely

High Availability

  • Azure Managed Redis: Use Standard or Premium tier for replication
  • AWS ElastiCache: Enable Multi-AZ with automatic failover
  • Self-hosted: Use Redis Sentinel or Redis Cluster for HA

Security

  • Always use TLS (rediss:// URL scheme or tls: {} in options) for cloud-hosted Redis
  • Use strong passwords and rotate them regularly
  • Restrict network access to Redis (VNet/VPC peering, security groups)
  • Never expose Redis ports to the public internet

Dependencies

  • ioredis — Feature-rich Redis client for Node.js
  • @memberjunction/coreILocalStorageProvider interface and logging utilities
  • @memberjunction/global — Global object store utilities

Related Packages