# Replica databases

[Wiki](../README.md) / [Operations](README.md)

**On this page**

- [Creating a replica](#creating-a-replica)
- [How it follows](#how-it-follows)
- [Managing replicas](#managing-replicas)
- [Restarts, restores and failures](#restarts-restores-and-failures)
- [Limits in this release](#limits-in-this-release)

A replica is a read-only copy of another database on the same instance, from
version 1.4.0. It is
kept up to date from the source's [change stream](streams.md) a few
milliseconds after each commit. Use it to serve reads and reports, as a
standby, or, with `applyDelay`, as a delayed copy that protects against an
accidental mass delete.

## Creating a replica

The source must have its change stream on, which needs `GDB_CHANGE_STREAMS=on`:

```cypher
ALTER DATABASE orders SET CHANGE STREAM ON;
CREATE DATABASE orders_ro AS REPLICA OF DATABASE orders;
CREATE DATABASE orders_standby AS REPLICA OF DATABASE orders
  OPTIONS {mode: 'backup', applyDelay: '1h'};
```

| Option | Default | Meaning |
|---|---|---|
| `mode` | `'readonly'` | `'readonly'` or `'backup'`. Both serve reads under normal permissions; `backup` marks a standby |
| `applyDelay` | none | Apply each source transaction only once it is this old |

Creating a replica takes a consistent copy of the source at a known
transaction, made durable at the source first, then follows from exactly that
transaction. It needs `CREATE DATABASE` and `ALTER DATABASE` on the source,
and it counts towards the edition's database limit.

## How it follows

- **Same transaction numbers:** each source transaction is written to the
  replica's own commit log under the **same transaction number** and applied
  the way crash recovery applies it. The replica's position is its last
  transaction number, so no transaction is ever applied twice.
- **Identical copy:** the replica is the same graph, with the same ids,
  indexes and constraints. A test checks that the replica's dump is
  byte-identical to the source's.
- **How quickly:** a replica only applies transactions that are durable at the
  source, so it can never be ahead of what the source has safely on disk. With
  `group` or `sync` durability it follows within a few milliseconds (measured
  p50 4 ms in a Linux container, including one Bolt round trip). With
  `buffered` durability, the Docker image's default, it follows the periodic
  sync, every `GDB_SYNC_INTERVAL_MS` (50 ms by default), so about 60 ms.
- **Read-only:** every write to a replica fails with
  `Galactus.ClientError.Database.ReadOnlyReplica`, including schema changes,
  imports and `gdb.restore`.
- **Retention:** while a replica follows, the source's stream keeps everything
  the replica has not yet applied.

## Managing replicas

```cypher
SHOW REPLICAS;
ALTER DATABASE orders_ro PAUSE REPLICATION;
ALTER DATABASE orders_ro RESUME REPLICATION;
ALTER DATABASE orders_ro RESYNC;     // re-copy from the source as it is now
ALTER DATABASE orders_ro PROMOTE;    // stop following, become writable
DROP DATABASE orders_ro;
```

`SHOW REPLICAS` reports each replica's state (`following`, `paused`,
`diverged`, `failed` or `stopped`), its applied and the source's latest
transaction numbers, the lag in transactions, the apply delay, the commit time
of the last applied transaction, and any error.

## Restarts, restores and failures

- **Restarts:** after a restart a replica is read-only immediately and
  resumes from its last applied transaction.
- **Source restores:** if the source starts a new stream history (a restore,
  or its stream turned off and on), the replica stops as `diverged` and keeps
  serving its last consistent state. `RESYNC` copies the source again.
- **Errors:** an error while following is shown in `SHOW REPLICAS` and
  retried. It never affects the source.
- **Promotion:** `PROMOTE` turns a replica into an ordinary database. It
  stops following and accepts writes.

## Limits in this release

- **Same instance only:** a replica of a database on another server (`AS
  REPLICA OF 'bolt://…'`) is planned but not supported yet.
- **No change stream of its own:** a replica cannot yet have one, so cascading
  replicas, and subscriptions on a replica, are not supported.
- **Driver routing:** replicas are not advertised to drivers' routing. Address
  a replica by its database name.

## Related articles

[Change streams](streams.md) · [Subscriptions](subscriptions.md) · [Backup, restore and transfer](backups.md)
