Operations

Backup and restore

Back up a graph to a compressed archive on the server and restore it as a new graph.

Summary

Online

The graph keeps accepting reads and writes during a backup.

Contents

The archive holds the graph’s stored data, including the history log, schema and indexes.

Restore

Creates a new graph from an archive and refuses if the name already exists.

Integrity check on open

When the restored graph opens, its files are checked against their integrity hashes, and the restore fails if any file differs.

Safety

Restore rejects archive entries with absolute paths, .. components, symbolic links, or hard links.

Managed cloud

Managed cloud: contact support to request a backup, export or restore of a graph.

Self-host

On a self-hosted server, an admin runs backup and restore over HTTP. Both endpoints require an admin key, and both read or write files on the server.

POST /graphs/{name}/backup

Flushes the graph, then writes a gzip-compressed tar archive of the graph to a path on the server. The graph keeps accepting reads and writes during the backup. From 1.4.3.3 the archive also holds a file that a write created for the first time while the backup was taking its cut (for example the catalog of the graph’s first index or constraint, or a first access policy); before, the archive could hold the write without that file. The same applies to clones.

Requires an admin key. output_path is a path on the server and must be inside the backup directory the operator has configured; if none is configured, every path is refused.

Request body — JSON:

{ "output_path": "/var/backups/invariantdb/my-graph-2026-07-10.tar.gz" }

Response — JSON on success, HTTP 200:

{ "output_path": "/var/backups/invariantdb/my-graph-2026-07-10.tar.gz", "bytes": 4183429120 }

Archive contents. The archive is a gzipped tar of the graph’s stored files. It contains:

Copy archives off the server for safekeeping.

POST /graphs/{name}/restore

Creates a new graph named {name} from an archive. It refuses if a graph with that name already exists, so it cannot overwrite a live graph. To replace an existing graph, restore under a new name first, then switch your callers to the new name.

Requires an admin key. input_path must be an existing file inside the configured backup directory.

Request body — JSON:

{ "input_path": "/var/backups/invariantdb/my-graph-2026-07-10.tar.gz" }

Response — JSON on success, HTTP 200:

{ "name": "my-graph-verify", "current_snapshot_seq": 4821 }

What restore does. Restore unpacks the archive into a new graph and opens it. Archive entries with absolute paths, .. components, symbolic links, or hard links are rejected. When the restored graph opens, its files are checked against their integrity hashes, and the restore fails if any file differs. The graph opens at the state the backup captured.

Errors. If the archive cannot be read, contains a rejected entry, or the name already exists, the request fails with HTTP 400 and a message describing the problem. If a file fails its integrity check, the request fails with HTTP 500 ("error": "storage") and a message that starts with snapshot integrity check failed. A failed restore can leave a partial graph under the new name; restore again under a different name.

Bitemporal history is included

InvariantDB records both when a fact was true (valid time) and when the system recorded it (recorded time). That history lives in an append-only log stored with the graph. It is the source for AT VALID, AT RECORDED, and OVER VALID BETWEEN queries, and for history-chain verification.

Each archive contains the history log. After a restore:

Point-in-time views are served at query time with AT VALID and AT RECORDED. You do not need to restore an old archive to see what the graph looked like last Tuesday; query the live graph with AT RECORDED <last Tuesday>. See Bitemporal queries.

Full archives

Each archive is a full copy of the graph’s stored files, with integrity hashes that are checked when the graph opens. It is not a delta against a previous archive. Two consequences:

Restore opens the graph at the state the backup captured. The history log carries earlier versions, so AT RECORDED queries for times before the backup return the same results on the restored graph.

Encryption at rest

On managed cloud, contact support for how archives are stored and encrypted.

On a self-hosted server, the archive is gzip-compressed but not encrypted. The server writes it to output_path; store it on an encrypted volume or in encrypted object storage.

Retention

Managed cloud: contact support for the retention of backups taken for you.

Self-hosted: the server never deletes archives. The operator decides how long to keep them.

Cross-region disaster recovery

Cross-region disaster recovery is not a self-service feature. If your workload needs cross-region recovery with a specific RTO and RPO, contact us.

What is available today:

Backup, restore, and verify example

End-to-end example on a self-hosted server. Replace <your-server> with your server’s address.

1. Take a backup

# Take a backup of the graph. The graph stays online. curl -fsS \ -H "Authorization: Bearer $ADMIN_API_KEY" \ -H "content-type: application/json" \ -X POST https://<your-server>/graphs/my-graph/backup \ -d '{"output_path":"/var/backups/invariantdb/my-graph-2026-07-10.tar.gz"}'

The response reports output_path and the number of bytes written.

2. Restore under a new name

# Restore into a new graph. Fails if my-graph-verify already exists. curl -fsS \ -H "Authorization: Bearer $ADMIN_API_KEY" \ -H "content-type: application/json" \ -X POST https://<your-server>/graphs/my-graph-verify/restore \ -d '{"input_path":"/var/backups/invariantdb/my-graph-2026-07-10.tar.gz"}'

A 200 means the archive was unpacked, its files passed the integrity check, and the graph is open. current_snapshot_seq identifies the restored state.

3. Check the restored graph on a schedule

Step 2 already checked the archive’s files when the graph opened. For an ongoing check, schedule a restore into a scratch graph on a cadence that matches your RPO.

4. Verify the history chain

curl -fsS \ -H "Authorization: Bearer $ADMIN_API_KEY" \ https://<your-server>/graphs/my-graph-verify/audit/verify # {"status":"clean","records":N,"last_seq":N}

Compare records and last_seq with the same call on my-graph. They match if my-graph has received no writes since the backup.

5. (Optional) Compare a specific belief

To check that a specific belief was restored, walk its revisions on both graphs and compare:

CALL db.beliefLineage("belief-99", 1) YIELD beliefId, claim, confidence, createdAt, supersededAt, depth, evidence RETURN beliefId, claim, confidence, createdAt, supersededAt, depth, evidence

Matching output on my-graph and my-graph-verify shows that the belief’s revisions and evidence were restored.

Backup and restore cover one graph on one server. For the current availability posture, see Availability.