Skip to content

Replication

Requires a license with the cluster feature. See pricing.

Beta. Keeping caches in step and the list of running replicas work. Known gaps:

  • The list of running replicas is read through the API only. The admin console has no screen for it.
  • Replication carries cache flushes and control notices only. Sessions, sign-in lockouts, rate limits and realtime events are shared between replicas only through Redis. See Scaling.

Each replica keeps permissions, content lists and license state in its own memory. Without replication, two replicas on one database drift apart until each cache expires: a permission rule saved on one is served stale by the other. With replication on, a change made on one replica reaches the others in about a second.

Replicas exchange short control messages through the database they already share, a handful a minute and never user traffic:

  • permission cache flushes
  • content cache flushes
  • license renewals
  • tenant feature changes
  • notices that other features send to their own copies on other replicas

Nothing else is needed: no Redis and no message broker, on PostgreSQL, MySQL and SQL Server alike. Each replica looks for new messages every second. A replica that was briefly unreachable catches up on what it missed when it returns, as long as it is back within ten minutes. Older messages are deleted.

This needs a license with cluster on every replica, and a super admin token in TOKEN. The quickstart shows how to get one.

  1. Start every replica against the same database. If you set LYEVE_PLUGINS, include cluster on each one. See licensing and tiers.

  2. List the running replicas:

    Terminal window
    curl http://localhost:3001/api/admin/cluster/instances \
    -H "Authorization: Bearer $TOKEN"
    {
    "count": 2,
    "instances": [
    {
    "instance_id": "lyeve-7f4c9b2-1",
    "hostname": "lyeve-7f4c9b2",
    "started_at": "2026-09-28T04:11:02Z",
    "last_heartbeat": "2026-09-28T04:19:57Z",
    "version": "v0.50.4",
    "listen_addr": ":3002",
    "status": "running"
    }
    ]
    }
  3. Stop one replica cleanly and list again. It leaves the list at once.

Each replica sends a heartbeat every five seconds, and a replica is listed while its last heartbeat is under fifteen seconds old.

VariableWhat it doesDefault
INSTANCE_IDThe name this replica shows in the roster and stamps on the messages it sends. Set it for stable names, such as the pod name.hostname and process id
SymptomCause and fix
A replica is missing from the listIt has not sent a heartbeat for fifteen seconds, or it runs without cluster. Check its logs and its LYEVE_PLUGINS.
A replica fails to start with a message about the databaseReplication needs the shared database. Check that replica's DATABASE_URL.
503 with could not read the cluster rosterThe database did not answer. Retry.
403 on the instances routeThe caller is not a super admin.