Empower your AI to directly edit documents in real time. Now production ready.
Read moreTiptap AI Toolkit - Empower your AI to directly edit documents in real time. | Product Hunt

Redis

VersionDownloadsLicenseChat

Hocuspocus can be scaled horizontally using the Redis extension. You can spawn multiple instances of the server behind a load balancer and sync changes and awareness states through Redis. Hocuspocus will propagate all received updates to all other instances using Redis and thus forward updates to all clients of all Hocuspocus instances.

The Redis extension does not persist data; it only syncs data between instances. Use the Database extension to store your documents.

Please note that all messages will be handled on all instances of Hocuspocus, so if you are trying to reduce cpu load by spawning multiple servers, you should not connect them via Redis.

Thanks to @tommoor for writing the initial implementation of that extension.

Installation

Install the Redis extension with:

npm install @hocuspocus/extension-redis

Configuration

For a full documentation on all available Redis and Redis cluster options, check out the ioredis API docs.

import { Server } from "@hocuspocus/server";
import { Redis } from "@hocuspocus/extension-redis";

const server = new Server({
  extensions: [
    new Redis({
      // [required] Hostname of your Redis instance
      host: "127.0.0.1",

      // [required] Port of your Redis instance
      port: 6379,

      // [optional] Maximum time in milliseconds to wait for the current state
      // from another instance when loading a document. Defaults to 1000.
      awaitInitialSyncTimeout: 1000,
    }),
  ],
});

server.listen();

Consistent state on load

When an instance loads a document that is already open on another instance, the Redis extension waits for that instance to send its current state. This ensures that newly connected clients and direct connections receive changes that may not have been persisted yet. If no other instance has the document open, loading is not delayed.

The awaitInitialSyncTimeout option limits how long the extension waits, in milliseconds. It defaults to 1000. Set it to 0 to disable waiting and use fire-and-forget synchronization instead.

Usage

The Redis extension works well with the database extension. Once an instance stores a document, it’s blocked for all other instances to avoid write conflicts.

import { Server } from "@hocuspocus/server";
import { Logger } from "@hocuspocus/extension-logger";
import { Redis } from "@hocuspocus/extension-redis";
import { SQLite } from "@hocuspocus/extension-sqlite";

// Server 1
const server = new Server({
  name: "server-1", // make sure to use unique server names
  port: 1234,
  extensions: [
    new Logger(),
    new Redis({
      host: "127.0.0.1", // make sure to use the same Redis instance :-)
      port: 6379,
    }),
    new SQLite(),
  ],
});

server.listen();

// Server 2
const anotherServer = new Server({
  name: "server-2",
  port: 1235,
  extensions: [
    new Logger(),
    new Redis({
      host: "127.0.0.1",
      port: 6379,
    }),
    new SQLite(),
  ],
});

anotherServer.listen();