npm package: @meui-creative/payload-redis-cache
Description: Redis caching plugin for Payload CMS with automatic invalidation
Latest version: 0.1.1

# Payload Redis Cache Plugin

A high-performance Redis-based caching plugin for [Payload CMS](https://payloadcms.com) with automatic cache invalidation and flexible configuration.

## Features

- 🚀 **Redis Caching**: Fast in-memory caching for Local API operations
- 🔄 **Auto Invalidation**: Automatic cache invalidation on document changes/deletes
- ⚙️ **Flexible Configuration**: Per-collection/global cache strategies
- 🏷️ **Tag-based Invalidation**: Intelligent cache invalidation using tags
- 📊 **Cache Statistics**: Built-in cache statistics and monitoring
- 🔧 **Manual Cache Management**: Utilities for programmatic cache control
- 🛡️ **Error Resilient**: Graceful fallback when Redis is unavailable

## Requirements

- **Payload CMS**: ^3.37.0
- **Redis**: 5.0+ (local or cloud instance)
- **Node.js**: ^18.20.2 || >=20.9.0

## Installation

```bash
npm install @meui-creative/payload-redis-cache redis
# or
yarn add @meui-creative/payload-redis-cache redis
# or
pnpm add @meui-creative/payload-redis-cache redis
```

## Quick Start

### 1. Configure the Plugin

```typescript
// payload.config.ts
import { payloadRedisCache } from '@meui-creative/payload-redis-cache'

export default buildConfig({
    // ... your config
    plugins: [
        payloadRedisCache({
            redis: {
                url: 'redis://localhost:6379'
            },
            collections: {
                posts: true,
                products: {
                    ttl: 1800, // 30 minutes
                    operations: ['find', 'findByID']
                }
            },
            globals: {
                settings: true
            }
        })
    ]
})
```

### 2. Use Cached Operations

```typescript
import { cachedFind, cachedFindByID } from '@meui-creative/payload-redis-cache'

// In your application code
const posts = await cachedFind(payload, {
    collection: 'posts',
    where: { status: { equals: 'published' } }
})

const post = await cachedFindByID(payload, {
    collection: 'posts',
    id: 'post-id'
})
```

## Configuration

### Plugin Options

```typescript
interface PayloadRedisCacheConfig {
    redis: {
        url: string                    // Redis connection URL
        options?: RedisClientOptions   // Additional Redis options
    }

    cache?: {
        defaultTTL?: number           // Default TTL in seconds (default: 3600)
        keyPrefix?: string            // Cache key prefix (default: 'payload:')
        debug?: boolean               // Enable debug logging (default: false)
    }

    collections?: {
        [slug]: boolean | CacheStrategy
    }

    globals?: {
        [slug]: boolean | CacheStrategy
    }

    invalidation?: {
        autoInvalidate?: boolean      // Auto-invalidate on changes (default: true)
        patterns?: InvalidationPattern[]
    }

    disabled?: boolean              // Disable plugin completely
}
```

### Cache Strategy Options

```typescript
interface CacheStrategy {
    ttl?: number                    // TTL in seconds
    enabled?: boolean               // Enable/disable caching
    operations?: CacheOperation[]   // Operations to cache
    tags?: string[]                 // Custom cache tags
}

type CacheOperation = 'find' | 'findByID' | 'count' | 'findGlobal'
```

### Configuration Examples

#### Basic Configuration
```typescript
payloadRedisCache({
    redis: { url: 'redis://localhost:6379' },
    collections: {
        posts: true,        // Use defaults
        products: true,
        users: false        // Don't cache users
    }
})
```

#### Advanced Configuration
```typescript
payloadRedisCache({
    redis: {
        url: process.env.REDIS_URL,
        options: {
            password: process.env.REDIS_PASSWORD,
            db: 1
        }
    },
    cache: {
        defaultTTL: 3600,
        keyPrefix: 'myapp:',
        debug: process.env.NODE_ENV === 'development'
    },
    collections: {
        posts: {
            ttl: 1800,                           // 30 minutes
            operations: ['find', 'findByID'],    // Only cache these operations
            tags: ['content']                    // Custom tags
        },
        products: {
            ttl: 7200,                           // 2 hours
            operations: ['find', 'findByID', 'count']
        }
    },
    globals: {
        settings: { ttl: 86400 }               // 24 hours
    }
})
```

## Usage Examples

### Cached Operations

```typescript
import {
    cachedFind,
    cachedFindByID,
    cachedCount,
    cachedFindGlobal
} from '@meui-creative/payload-redis-cache'

// Cached collection operations
const posts = await cachedFind(payload, {
    collection: 'posts',
    where: { status: { equals: 'published' } },
    limit: 10,
    sort: '-createdAt'
})

const post = await cachedFindByID(payload, {
    collection: 'posts',
    id: 'post-id',
    depth: 2
})

const count = await cachedCount(payload, {
    collection: 'posts',
    where: { status: { equals: 'published' } }
})

// Cached global operations
const settings = await cachedFindGlobal(payload, {
    slug: 'settings',
    depth: 1
})
```

### Manual Cache Management

```typescript
import {
    invalidateCollection,
    invalidateGlobal,
    clearAllCache,
    getCacheStats
} from '@meui-creative/payload-redis-cache'

// Invalidate specific collection
await invalidateCollection(payload, 'posts')
await invalidateCollection(payload, 'posts', 'specific-id')

// Invalidate global
await invalidateGlobal(payload, 'settings')

// Clear all cache
await clearAllCache(payload)

// Get cache statistics
const stats = await getCacheStats(payload)
console.log(`Cache keys: ${stats.keys}, Memory: ${stats.memory}`)
```

### Custom Cache Operations

```typescript
import { setCacheData, getCacheData } from '@meui-creative/payload-redis-cache'

// Set custom cache data
await setCacheData(payload, 'custom:key', { data: 'value' }, 3600, ['custom'])

// Get custom cache data
const data = await getCacheData(payload, 'custom:key')
```

## How It Works

### Automatic Cache Invalidation
The plugin hooks into Payload's `afterChange` and `afterDelete` hooks to automatically invalidate related cache entries when documents are modified or deleted.

### Cache Keys
Cache keys are generated based on:
- Collection/Global slug
- Operation type (find, findByID, etc.)
- Operation parameters (where clauses, depth, locale, etc.)
- Document ID (for findByID operations)

Example cache keys:
```
payload:collection:posts:find:eyJ3aGVyZSI6eyJzdGF0dXMiOnsiZXF1YWxzIjoicHVibGlzaGVkIn19fQ==
payload:collection:posts:findByID:post-123
payload:global:settings:findGlobal
```

### Cache Tags
Cache entries are tagged for efficient invalidation:
- `collection:posts` - All posts collection entries
- `collection:posts:123` - Specific post with ID 123
- `global:settings` - Settings global entries

## Performance Considerations

### Redis Connection
- Uses a single Redis connection per Payload instance
- Automatic reconnection on connection loss
- Connection pooling handled by Redis client

### Cache Size Management
- TTL-based expiration prevents unlimited growth
- Manual cache clearing utilities available
- Monitor cache size using `getCacheStats()`

### Error Handling
- Graceful fallback to regular Payload operations if Redis unavailable
- Errors logged but don't break application functionality
- Cache operations are non-blocking

## Environment Variables

```bash
# Redis connection
REDIS_URL=redis://localhost:6379

# Redis with authentication
REDIS_URL=redis://username:password@localhost:6379

# Redis Cloud
REDIS_URL=redis://your-redis-cloud-endpoint:6379
```



## Troubleshooting

### Common Issues

**Redis connection failed**
- Ensure Redis is running and accessible
- Check REDIS_URL environment variable
- Verify network connectivity and firewall settings

**Cache not working**
- Check plugin configuration
- Verify collections/globals are enabled for caching
- Enable debug logging to see cache operations

**Memory usage high**
- Reduce TTL values
- Implement cache size limits in Redis configuration
- Use `clearAllCache()` periodically

### Debug Mode

Enable debug logging to monitor cache operations:

```typescript
payloadRedisCache({
    cache: { debug: true },
    // ... other config
})
```

This will log:
- Cache hits and misses
- Cache setting operations
- Cache invalidation operations
- Error messages

## License

MIT License - see LICENSE file for details.

---

**Made with ❤️ by [MEUI Creative](https://meui-creative.com)**