Redis
Setting up Redis for caching, session storage, and horizontal scaling in LibreChat
This guide covers how to configure Redis for caching and session storage in LibreChat. Redis provides significant performance improvements and is required for horizontal scaling. If you're running multiple LibreChat instances behind a load balancer, Redis ensures consistent state across all instances.
Table of Contents
- Basic Setup
- Connection Types
- Security Configuration
- Advanced Options
- Replica Failover Recovery
- Health Checks
- Performance Tuning
- Advanced Connection Tuning
- Configuration Examples
- Resumable Streams
- Generation Protocol Compatibility
- Stream Delta Coalescing
- MCP Catalog Coordination
Basic Setup
Enable Redis
To enable Redis in LibreChat, set the following environment variable in your .env file:
USE_REDIS=trueImportant: When USE_REDIS=true, you must also provide a REDIS_URI. The application will throw an error if Redis is enabled without a connection URI.
Connection Types
Single Redis Instance
For a standard single Redis server setup:
# Local Redis instance
REDIS_URI=redis://127.0.0.1:6379
# Remote Redis instance
REDIS_URI=redis://your-redis-host:6379Redis Cluster
For Redis cluster deployments with multiple nodes:
# Multiple Redis cluster nodes
REDIS_URI=redis://127.0.0.1:7001,redis://127.0.0.1:7002,redis://127.0.0.1:7003The application automatically detects cluster mode when multiple URIs are provided.
If your redis cluster only has a single URI, you can use the USE_REDIS_CLUSTER environment variable to enable cluster mode:
# Redis cluster with single URI
REDIS_URI=redis://127.0.0.1:7001
USE_REDIS_CLUSTER=trueSingle-Endpoint Managed Redis Services
Some managed Redis services, including AWS ElastiCache Serverless and Redis Enterprise Cloud on AWS, expose a single connection endpoint while sharding keys internally. In that setup, keep LibreChat in single-node connection mode, but enable cluster-safe deletes if cache clears fail with CROSSSLOT Keys in request don't hash to the same slot.
USE_REDIS=true
REDIS_URI=rediss://your-managed-redis-endpoint:6379
USE_REDIS_CLUSTER=false
REDIS_CLUSTER_SAFE_DELETE=trueREDIS_CLUSTER_SAFE_DELETE=true makes LibreChat delete matching cache keys one at a time instead of sending multi-key DEL commands. This avoids CROSSSLOT errors without changing how LibreChat connects to Redis.
Use USE_REDIS_CLUSTER=true only when LibreChat should create a Redis Cluster client. For single-endpoint managed services, REDIS_CLUSTER_SAFE_DELETE=true is the safer option.
Redis with TLS/SSL
For secure Redis connections:
# Redis with TLS encryption
REDIS_URI=rediss://127.0.0.1:6380
# Path to CA certificate for TLS verification
REDIS_CA=/path/to/ca-cert.pemSecurity Configuration
Authentication
Configure Redis authentication credentials:
# Method 1: Include credentials in URI
# With both username and password
REDIS_URI=redis://myuser:[email protected]:6379
# Method 2: Separate environment variables
REDIS_URI=redis://127.0.0.1:6379
REDIS_USERNAME=your_redis_username
REDIS_PASSWORD=your_redis_passwordNote: Credentials embedded in REDIS_URI take precedence. REDIS_USERNAME and REDIS_PASSWORD are only used as a fallback when the URI has no username or password.
TLS Configuration
For encrypted connections:
# Enable TLS with rediss:// protocol
REDIS_URI=rediss://your-redis-host:6380
# Provide CA certificate for verification
REDIS_CA=/path/to/your/ca-certificate.pemTLS with Elasticache
Elasticache may need to use an alternate dnsLookup for TLS connections. see "Special Note: Aws Elasticache Clusters with TLS" on this webpage: https://www.npmjs.com/package/ioredis
# Enable redis alternate dnsLookup
REDIS_USE_ALTERNATIVE_DNS_LOOKUP=trueAdvanced Options
Key Prefixing
Redis key prefixing prevents cross-deployment contamination by isolating cache data between different environments, versions, or instances sharing the same Redis server. This is essential for:
- Multi-tenant deployments: Separate staging, production, and development environments
- Blue-green deployments: Isolate cache between different application versions
# Option 1: Dynamic prefix from environment variable (recommended for cloud)
# Google Cloud Platform - Cloud Run
REDIS_KEY_PREFIX_VAR=K_REVISION
# AWS - ECS/Fargate
REDIS_KEY_PREFIX_VAR=AWS_EXECUTION_ENV
# Azure Container Instances
REDIS_KEY_PREFIX_VAR=CONTAINER_NAME
# Kubernetes - Pod name or deployment
REDIS_KEY_PREFIX_VAR=HOSTNAME
REDIS_KEY_PREFIX_VAR=POD_NAME
# Kubernetes - Custom deployment identifier
REDIS_KEY_PREFIX_VAR=DEPLOYMENT_ID
# Heroku
REDIS_KEY_PREFIX_VAR=DYNO
# Option 2: Static prefix (for manual control)
REDIS_KEY_PREFIX=librechat-prod-v2
REDIS_KEY_PREFIX=staging-branch-feature-x
REDIS_KEY_PREFIX=dev-john-localImportant: You cannot set both REDIS_KEY_PREFIX_VAR and REDIS_KEY_PREFIX simultaneously.
Examples of contamination without prefixing:
- Production cache overwritten by staging deployment
- Feature branch tests corrupting main branch cache
- Old deployment versions serving stale cached data
Key prefixing format:
- IoRedis client:
{prefix}::{key} - Keyv client: Handled by the store layer
Connection Limits
Configure Redis connection limits:
# Maximum number of event listeners (default: 40)
REDIS_MAX_LISTENERS=40Connection Keep-Alive
Configure deadline-bounded Redis heartbeats and TCP keepalive:
# Redis ping interval in seconds (default: 0 = disabled)
# When set to a positive integer (in seconds), Redis clients will ping the server at this interval
# When unset or 0, no pinging is performed (recommended for most use cases)
# Example: 300 = ping every 5 minutes
REDIS_PING_INTERVAL=300
# Maximum time an enabled heartbeat PING may go unanswered (default: 5000 ms)
REDIS_PING_TIMEOUT=5000
# Dedicated pub/sub subscriber heartbeat (default: 15 seconds, 0 = disabled)
REDIS_SUBSCRIBER_PING_INTERVAL=15
# TCP keepalive idle delay for ioredis sockets (default: 10000 ms, 0 = kernel default)
REDIS_KEEP_ALIVE=10000Important:
- Setting
REDIS_PING_INTERVAL=0or omitting it disables pinging entirely - Only set a positive value (in seconds) if you experience connection timeout issues
REDIS_PING_INTERVALis specified in seconds and controls the optional main ioredis heartbeat- Dedicated pub/sub subscribers use their own default-on interval because an idle dead socket may otherwise remain undetected; set
REDIS_SUBSCRIBER_PING_INTERVAL=0to disable that heartbeat - Every enabled heartbeat uses
REDIS_PING_TIMEOUTas its response deadline and reconnects the socket when a PING remains unanswered REDIS_KEEP_ALIVEconfigures the ioredis TCP socket independently from application-level PINGs- Example values:
300(5 minutes),600(10 minutes),60(1 minute)
Replica Failover Recovery
During a Sentinel failover, a demoted Redis replica can keep an existing socket open while rejecting writes with READONLY. LibreChat detects this response on the non-cluster Keyv client, tears down the stale connection, and reconnects so the current primary can be resolved without restarting the application.
# Minimum interval between forced recovery attempts, in milliseconds
# Default: 5000
REDIS_READONLY_RECOVERY_INTERVAL=5000The interval debounces reconnect attempts during a burst of failed writes. Redis Cluster clients are excluded because they use native cluster topology and redirect handling.
Health Checks
LibreChat serves three probe endpoints. Only /readyz reflects Redis:
| Endpoint | Returns 200 OK | Returns 503 NOT_READY |
|---|---|---|
/livez | Whenever the process is serving requests | Never |
/health | Whenever the process is serving requests | Never |
/readyz | After startup completes and, with USE_REDIS=true, while Redis is connected | Before startup completes, or while Redis is enabled but disconnected |
When Redis restarts, fails over, or becomes unreachable for longer than the client's retry window, requests that depend on it (sign-in, sessions, rate limits) fail until the connection returns. During that time /readyz answers 503, so a load balancer or Kubernetes readiness probe stops routing traffic to the instance. It returns to 200 as soon as Redis reconnects, without a restart. With Redis enabled, every Redis client must be connected; for a Redis Cluster, that includes every primary node.
Point readiness checks at /readyz and liveness checks at /livez. Keep Redis out of the liveness check: a liveness probe that fails during a Redis outage restarts every pod at once and cannot bring Redis back.
livenessProbe:
httpGet:
path: /livez
port: 3080
readinessProbe:
httpGet:
path: /readyz
port: 3080
periodSeconds: 10
failureThreshold: 3/readyz does not wait out short reconnects on its own, so use failureThreshold to decide how long an outage lasts before traffic is withdrawn.
Selective In-Memory Caching
Force specific cache namespaces to use in-memory storage even when Redis is enabled:
# Comma-separated list of cache keys
FORCED_IN_MEMORY_CACHE_NAMESPACES=CONFIG_STORE,APP_CONFIG,ROLESWhen unset, the default is CONFIG_STORE,APP_CONFIG, so configuration derived from librechat.yaml stays per-container. Setting this variable replaces the default rather than adding to it, so include CONFIG_STORE,APP_CONFIG in your list unless you want those namespaces in Redis. Set it to an empty string to route every namespace through Redis.
Valid cache keys (from the CacheKeys enum in librechat-data-provider):
| Key | Description |
|---|---|
CONFIG_STORE | Configuration store |
TOOL_CACHE | Tool cache (plugins, MCP tools, tool definitions) |
ROLES | User roles |
USER_PRINCIPALS | Group memberships used to resolve ACL principals |
PROMPT_GROUPS_ACCESS | Prompt group access ID sets |
AGENT_LINKED_INSTRUCTIONS | Resolved instructions of an agent's linked prompt groups |
SANDBOX_PREWARM | Per-conversation code sandbox prewarm state |
GEN_TITLE | Generated titles |
TOOLS | Tools data |
MODELS_CONFIG | Models configuration |
MODEL_QUERIES | Model queries |
STARTUP_CONFIG | Startup configuration |
ENDPOINT_CONFIG | Endpoint configuration |
TOKEN_CONFIG | Token configuration |
REASONING_CAPABILITIES | Per-model reasoning effort for OpenRouter endpoints |
PULL_REQUESTS | Pull request lookups and GitHub rate limit cooldowns |
APP_CONFIG | Application configuration |
ABORT_KEYS | Abort keys |
BANS | Ban data |
ENCODED_DOMAINS | Encoded domains |
AUDIO_RUNS | Audio processing runs |
MESSAGES | In-progress messages |
FLOWS | In-progress flow states |
PENDING_REQ | Pending requests |
S3_EXPIRY_INTERVAL | S3 expiry intervals |
OPENID_EXCHANGED_TOKENS | OpenID exchanged tokens |
AUTH_USER_DOC | Cached authenticated user documents |
OPENID_SESSION | OpenID sessions |
SAML_SESSION | SAML sessions |
ADMIN_OAUTH_EXCHANGE | Admin panel OAuth exchange codes |
PASSKEY_CHALLENGE | Pending passkey ceremony challenges |
Invalid keys
Using an invalid key (e.g., the deprecated STATIC_CONFIG) will cause a startup error. Only use
keys from the table above.
Performance Tuning
Connection Keep-Alive
The application implements configurable connection keep-alive:
- Main-client PINGs are controlled by
REDIS_PING_INTERVALand disabled by default - Dedicated subscriber PINGs are controlled by
REDIS_SUBSCRIBER_PING_INTERVALand default to 15 seconds - Heartbeats use
REDIS_PING_TIMEOUTto detect silently dead sockets and force reconnection - TCP keepalive uses
REDIS_KEEP_ALIVE, independently of application-level heartbeats - Heartbeat timers are cleared on disconnect or close events
Cache Strategy
The application uses a dual-client approach:
- IoRedis client: Primary Redis operations with automatic prefixing
- Keyv Redis client: Store-layer operations with prefix handling in
cacheFactory.js
Advanced Connection Tuning
These optional variables tune connection behavior and bulk cache operations. The defaults suit most deployments.
| Variable | Default | Description |
|---|---|---|
REDIS_CONNECT_TIMEOUT | 10000 | Connection timeout in milliseconds. |
REDIS_RETRY_MAX_ATTEMPTS | 10 | Maximum reconnection attempts before giving up. 0 retries indefinitely. |
REDIS_RETRY_MAX_DELAY | 3000 | Maximum delay between reconnection attempts, in milliseconds. |
REDIS_ENABLE_OFFLINE_QUEUE | true | Queue commands while disconnected. Set to false to fail them immediately. |
REDIS_SCAN_COUNT | 1000 | COUNT hint for SCAN operations when finding keys by pattern. |
REDIS_DELETE_CHUNK_SIZE | 1000 | Number of keys deleted per batch in bulk deletes. |
MCP_REGISTRY_CACHE_TTL | 5000 | Milliseconds MCP registry caches are kept. Cross-instance staleness can reach twice this value. 0 disables the local snapshot, so every read goes to Redis. |
Memory Optimization
Use FORCED_IN_MEMORY_CACHE_NAMESPACES to optimize performance by keeping frequently accessed, small datasets in memory while using Redis for larger caches.
Configuration Examples
Development Setup
USE_REDIS=true
REDIS_URI=redis://127.0.0.1:6379
REDIS_KEY_PREFIX=librechat-devProduction Setup
USE_REDIS=true
REDIS_URI=rediss://prod-redis.company.com:6380
REDIS_USERNAME=librechat_user
REDIS_PASSWORD=secure_password_here
REDIS_CA=/etc/ssl/redis-ca.pem
REDIS_KEY_PREFIX_VAR=DEPLOYMENT_ID
REDIS_MAX_LISTENERS=100
REDIS_PING_INTERVAL=300
FORCED_IN_MEMORY_CACHE_NAMESPACES=CONFIG_STORE,APP_CONFIG,ROLES,MESSAGESCluster Setup
USE_REDIS=true
REDIS_URI=redis://cluster-node1:7001,redis://cluster-node2:7002,redis://cluster-node3:7003
REDIS_USERNAME=cluster_user
REDIS_PASSWORD=cluster_password
REDIS_KEY_PREFIX=librechat-clusterResumable Streams
Redis enables Resumable Streams for horizontally scaled deployments. When enabled, AI responses can seamlessly reconnect and resume across server instances.
Important: When USE_REDIS=true, resumable streams automatically use Redis for cross-instance coordination. This is the recommended setup for horizontally scaled deployments where users might connect to different server instances.
Note: If you're running a single LibreChat instance, Redis for resumable streams is typically overkill; the built-in in-memory mode works fine. Redis becomes essential when you have multiple LibreChat instances behind a load balancer, where a user's reconnection might hit a different server than where their stream started.
Configuration
# Redis enabled = resumable streams automatically use Redis
USE_REDIS=true
REDIS_URI=redis://127.0.0.1:6379
# Optional: explicitly control resumable streams behavior
# USE_REDIS_STREAMS=true # Enabled by default when USE_REDIS=trueGeneration Protocol Compatibility
Current LibreChat clients negotiate generation protocol v2 automatically with every built-in generation store. No deployment setting is required. Existing generations with an explicit or stored protocol-v1 marker keep their immutable v1 behavior through steering, pause/resume, retry, and recovery until they finish.
For a rolling upgrade, every running API and worker image must include the v2 compatibility bridge:
- Every API and worker image runs LibreChat
v0.8.8-rc1or newer. - Helm chart
2.0.8or newer selects a compatible default image; a custom image override must still meet the image requirement above.
When upgrading from an older release, perform a cold handoff: stop every old API and worker replica before starting the new image. This prevents pre-v2 and automatic-v2 binaries from sharing generation state in Redis.
Rolling deployment safety
Do not run a release older than v0.8.8-rc1 against the same Redis generation state as current replicas. Before rolling back below that compatibility floor, first ensure current replicas and protocol-v2 generations have drained.
In-memory generation streams also negotiate protocol v2 automatically and do not share generation state across processes.
Stream Delta Coalescing
Redis-backed streams can batch delta publications to reduce Redis scripts, round trips, and CPU at high token rates:
STREAM_DELTA_COALESCE_MS=25The setting defaults to 25 milliseconds when unset. Set it explicitly to 0 to disable coalescing; values above 1000 are capped. Batching can add up to one configured window of delivery latency and may lose the buffered tail if the publishing process exits before it flushes. Individual chunk frames are retained for protocol compatibility, so this setting reduces Redis script and round-trip work without changing the subscriber frame format. In-memory generation streams are unchanged.
Key Benefits (for Horizontal Scaling)
- Cross-instance continuity: Users can start a generation on one server and resume on another
- Rolling deployments: Active streams survive server restarts
- Multi-tab sync: Same conversation syncs across multiple browser tabs in a load-balanced environment
- Connection resilience: Automatic reconnection regardless of which server handles the request
Cluster Configuration
For Redis Cluster deployments, LibreChat automatically uses hash-tagged keys to ensure stream operations stay within the same cluster slot:
USE_REDIS=true
USE_REDIS_STREAMS=true
USE_REDIS_CLUSTER=true
REDIS_URI=redis://node1:7001,redis://node2:7002,redis://node3:7003See Resumable Streams for more details on this feature.
MCP Catalog Coordination
When Redis is enabled, LibreChat coordinates application-level MCP tool catalogs across replicas. Startup publication, reconnect synchronization, and notifications/tools/list_changed updates use generation and revision markers so a stale replica cannot overwrite a newer catalog.
Redis Cluster deployments use slot-safe catalog keys and update operations; no separate MCP Redis setting is required. See MCP Server Management for dynamic catalog and OAuth readiness behavior.
How is this guide?