Skip to main content
LibreChat is joining ClickHouse to power the open-source Agentic Data Stack 🎉 Learn more
LibreChat

Resumable Streams

Recover in-progress AI responses after a dropped connection, sync the same chat across tabs and devices, and keep streams alive across scaled-out instances.

Resumable streams let an in-progress AI response survive a dropped connection. If the network drops, the browser refreshes, or you switch tabs or devices, LibreChat reconstructs the content that was already streamed and continues from where it left off. The same mechanism keeps multiple viewers of one conversation in sync.

What You Get

  • No lost responses. Network drops, browser refreshes, and server restarts do not discard streamed content.
  • Tabs stay in sync. Open one conversation in two browser tabs and both receive the same updates in real time.
  • Switch devices mid-stream. Start a generation on your desktop and pick up the result on your phone.
  • Background generations. Start a long response, move to another tab or app, and the full response is there when you return.
  • Shared conversations. Every viewer of a shared chat sees content stream in at the same time.

How It Works

When you send a message, LibreChat creates a generation job that records every streamed delta. If the connection breaks:

  1. The client detects the disconnection.
  2. On reconnect, the server rebuilds the content streamed so far from the job's recorded deltas.
  3. The missing content is delivered in a single sync event.
  4. Streaming continues from the current position.

This runs automatically and requires no user action.

Deployment Modes

LibreChat ships with two backends for resumable streams.

Single-Instance Mode (default)

Stores stream state in memory and uses a Node.js EventEmitter for pub/sub. This is the default and needs no configuration. It covers local development, single-server deployments, and Docker Compose setups.

Redis Mode (production)

Uses Redis Streams and Pub/Sub so stream state is shared across instances. Use it for horizontally scaled, load-balanced, or high-availability deployments, including Kubernetes clusters. With Redis, a generation started on one instance can resume on another, which keeps active streams alive through rolling deployments and auto-scaling.

Single instance? You likely don't need Redis here

In-memory mode handles everything for a single LibreChat instance. Redis becomes relevant once you run multiple instances behind a load balancer. Redis is still useful for caching and session storage in single-instance deployments, just not specifically for resumable streams.

Configuration

Enable Redis Streams

Setting USE_REDIS=true makes resumable streams use Redis automatically. Use USE_REDIS_STREAMS to control it explicitly.

USE_REDIS=true
REDIS_URI=redis://localhost:6379
# Resumable streams use Redis automatically when USE_REDIS=true.
# Set USE_REDIS_STREAMS to control it explicitly:
USE_REDIS_STREAMS=true

Redis Cluster

For a Redis Cluster, enable cluster mode and list the nodes in REDIS_URI.

USE_REDIS_STREAMS=true
USE_REDIS_CLUSTER=true
REDIS_URI=redis://node1:7001,redis://node2:7002,redis://node3:7003

LibreChat uses hash-tagged keys so that multi-key operations land on the same cluster slot.

What Gets Reconstructed

On reconnect, LibreChat aggregates the recorded delta events to rebuild:

  • Message content (text, tool calls, citations)
  • Agent run steps and intermediate reasoning
  • Metadata and state information

The storage mechanism depends on the deployment mode:

ComponentStorage Mechanism
ChunksRedis Streams (XADD/XRANGE)
Job metadataRedis Hash structures
Real-time eventsRedis Pub/Sub channels
ExpirationAutomatic TTL after stream completion

LibreChat applies a few optimizations to keep this cheap:

  • Memory-first recovery. Reconnecting to the same instance reads from local cache, avoiding a Redis round trip.
  • Cleanup on access. Stale job entries are removed during queries, and completed streams expire automatically.
  • Garbage-collected storage. In-memory mode stores stream graphs with WeakRef, so they are collected once a conversation ends.

Testing

To confirm the feature is working, start a streaming conversation with any model, then try one of:

  • Tabs. Open the same chat in a second tab; both should sync.
  • Disconnect. Drop the network briefly, then reconnect.
  • Navigation. Navigate away mid-stream, then return.

Each case should produce the complete response with no missing content.

Troubleshooting

Streams not resuming. Confirm Redis is reachable and that USE_REDIS_STREAMS is set.

docker exec -it librechat-redis redis-cli ping
# Expected: PONG

echo $USE_REDIS_STREAMS

Content appears duplicated. This usually means a client version mismatch. Update to the latest version of LibreChat.

High memory use in single-instance mode. Completed streams are garbage collected. If memory stays high, look for very long-running streams that never complete or streams that errored without cleaning up.

For implementation details, see PR #10926.

How is this guide?