Back up and restore a store
Take a consistent copy of a relate store with relate clone, even while a directory store is in use, check that it opens, and restore from it.
cli
Before you start: Install relate
This guide shows you how to back up a relate store A relate database: a directory, a single .rl file, or :memory:, opened with --database. Read more in the glossary, check that the backup opens, and restore from it. The backup command is relate clone: it opens the source read-only, never writes it, and writes the committed state into a new store. A directory store A store kept as a folder of snapshot files, a WAL folder and lock files; the layout for any --database path that is not :memory: and does not end in .rl. Read more in the glossary can be cloned while another process writes to it; a .rl file can be cloned or copied while no process has it open.
Prerequisites
- relate on your
PATH(Install relate). - A store to back up. The commands on this page use a directory store named
team, created from a small seed graph:
cat > team.cypher <<'EOF'
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
(grace:Person {name: 'Grace', role: 'engineer'}),
(noor:Person {name: 'Noor', role: 'maintainer'}),
(relate:Project {name: 'relate', language: 'Rust'}),
(tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
(ada)-[:WORKS_ON {since: 2024}]->(relate),
(grace)-[:WORKS_ON {since: 2023}]->(relate),
(grace)-[:WORKS_ON {since: 2022}]->(tck),
(noor)-[:MAINTAINS]->(relate),
(ada)-[:KNOWS]->(grace);
EOF
relate query --database ./team --mode envelope < team.cypherBack up a directory store
Clone the store into a new path. A destination ending in .rl gives a backup that is one file; any other path gives a directory store. When the source is a directory store, the destination's parent folder must exist; the destination itself must never exist:
mkdir backups
relate clone ./team ./backups/team-2026-11-07.rlrelate clone prints nothing on success. It reads the state committed at the moment it opens the source and does not follow later commits, so the copy is consistent even if a writer keeps going. The writer keeps its lock and keeps committing: a directory store allows read-only opens beside its writer, and clone opens the source that way.
If the store keeps its WAL Append-only log each commit goes to before it applies; under the default full durability mode it is synced first, so a crash loses no acknowledged write. Read more in the glossary (WAL) outside its folder (opened with --wal-dir), pass the same --wal-dir to relate clone.
Back up a single-file store
A .rl file allows no second opener while a writer holds it, so relate clone and --read-only opens are both refused until the writer exits. Back up a .rl store while no process has it open:
relate clone ./app.rl ./backups/app-2026-11-07.rlA .rl file holds its WAL inside it, so a plain copy of the file (cp) taken while nothing has it open is a complete backup too. relate clone writes a compact copy: a .rl file keeps the space it once needed, and the clone holds only the current state.
Check that the backup opens
Open the backup read-only An open mode (--read-only) that never writes, checkpoints or migrates the store; writes fail, and a directory store can be read beside its writer. Read more in the glossary and count what it holds. A read-only open never writes, checkpoints or migrates the store, so checking a backup leaves it as it was:
relate --database ./backups/team-2026-11-07.rl --read-only --mode envelope "MATCH (n) RETURN count(n) AS nodes"{"columnTypes":["INTEGER"],"columns":["nodes"],"notifications":[],"planCache":"miss","rows":[{"nodes":5}],"timings":{"elapsed_ms":0.46954199999999996,"execute_ms":0.309667,"lex_parse_ms":0.027375,"lower_ms":0.038708,"parse_ms":0.100791,"plan_ms":0.05025,"result_generation_ms":0.000292,"rewrite_ms":0.008042},"truncated":false}relate info reads the backup's metadata without opening it, including the node and relationship counts at its last checkpoint The step that writes a fresh snapshot of committed state and recycles old WAL segments: every 300 seconds by default, on clean exit, and on .checkpoint. Read more in the glossary:
relate info --database ./backups/team-2026-11-07.rllayout: .rl bundle
superblock version: 1
codec: parquet
format version: 3
checkpoint LSN: 1
commit timestamp: 1
total bytes: 32768
wal segments past checkpoint: 1
nodes (at checkpoint LSN 1): 5
relationships (at checkpoint LSN 1): 5
indexes: 0
constraints: 0Compare the counts with the source, and run a statement your application depends on. A backup is only as good as the last time it opened.
Restore from a backup
Stop every process that has the store open. Move the damaged store aside rather than deleting it, then clone the backup to the store's path:
mv ./team ./team-damaged
relate clone ./backups/team-2026-11-07.rl ./teamrelate clone writes either layout from either layout, so a .rl backup restores into a directory store, as ./team does, or into a .rl file. For a .rl store, copying the backup file into place works too. Start the application again once the restored store opens.
Copy files only when nothing has the store open
A directory store keeps two things: the snapshot files, which hold the state at the last checkpoint, and the WAL folder (wal/, or .cypherlite/wal/ in a markdown store), which holds every commit since. The WAL is the only copy of those recent commits until the next checkpoint: every 300 seconds by default, after 64 MiB of WAL or 10,000 commits, and when the store closes.
That has two consequences for a file copy:
- A file copy is consistent only when no commit is in progress, and
cpcannot tell.relate clonereads only complete commits. - A copy without its WAL folder holds the state at the last checkpoint. Commits made since are missing from it, and a read-only open of it fails.
When no process has the store open, a copy of the whole folder is a complete backup. The copy holds the snapshot files and the WAL folder:
cp -R ./team ./backups/team-folder-copy
ls ./backups/team-folder-copymanifest.json
nodes
relationships
walThe CLI checkpoints every time a writable run exits, so a store last written from the CLI has its state in the snapshot. A long-running process, such as an application using a client or relate serve, keeps recent commits in the WAL between checkpoints. Recover from a crash explains what the WAL gives back after a crash.
Schedule backups
Run relate clone from a scheduler with a dated destination, keep several generations, and open one now and then. A crontab entry (crontab -e) for an hourly clone of a directory store, with % escaped because cron treats it as a newline:
0 * * * * relate clone <store> <backup-dir>/team-$(date +\%Y\%m\%d-\%H).rlTake a backup before a newer relate release opens the store writable as well: that open migrates the store forward, and older releases can't open it afterward. Upgrade a store covers that.
Verify
The restored store opens and holds the graph:
relate --database ./team --read-only --mode envelope "MATCH (p:Person) RETURN p.name AS name ORDER BY name"{"columnTypes":["STRING"],"columns":["name"],"notifications":[],"planCache":"miss","rows":[{"name":"Ada"},{"name":"Grace"},{"name":"Noor"}],"timings":{"elapsed_ms":0.549375,"execute_ms":0.380625,"lex_parse_ms":0.030459,"lower_ms":0.040791,"parse_ms":0.10675000000000001,"plan_ms":0.053209,"result_generation_ms":0.000209,"rewrite_ms":0.007958000000000002},"truncated":false}If it goes wrong
-
Failed to clone database: storage error: clone destination already exists(exit code 1).relate clonenever overwrites. Cloning onto an existing backup fails:relate clone ./team ./backups/team-2026-11-07.rlFailed to clone database: storage error: clone destination already existsUse a new destination name, such as one with the date and hour in it.
-
Failed to clone database: storage error: clone destination parent does not exist: <path>(exit code 1). The source is a directory store and the destination's folder does not exist. Create it first (mkdir -p); a.rlsource creates the folders itself. -
Failed to clone database: storage locked: <path>(exit code 1). The source is a.rlfile and a process holds it. Back it up when that process exits, or keep the store as a directory store so it can be cloned while in use (Choose a store layout). -
storage error: read-only open requires an existing database at <path>(exit code 1). Nothing at that directory path is a store. Check the path. -
storage error: database not found: <path>(exit code 1). A--read-onlyopen of a.rlpath where no file exists. Check the backup's path. -
storage error: read-only open requires an existing WAL at <path>(exit code 1). A copied directory store is missing its WAL folder, named in the message. Copy the whole folder again, or take the backup withrelate clone. -
Failed to clone database: storage error: clone source must be a native directory or .rl bundle path(exit code 1). The source was:memory:. An in-memory store has nothing on disk to back up; write the data into a directory store or a.rlfile to keep it.
Related
- Storage formats: what a directory store and a
.rlfile hold. - Choose a store layout: which layout can be backed up while in use.
- Recover from a crash: what the WAL restores on its own.
- Upgrade a store: back up before a newer release migrates the store.