---
title: relate clone
description: "relate, the embedded Cypher graph database (relatedb.ai): The relate clone command that copies a store into a new one, between directory and .rl layouts and between codecs, with its flags, refusals and exit codes."
type: reference
surfaces:
  - cli
status: stable
verified: 0.1.2
verified_by:
  - cli
canonical_url: https://relatedb.ai/docs/reference/cli/clone/
prerequisites: []
related:
  - reference/cli/flags#relate-clone
  - reference/storage/formats
  - guides/storage/backup-and-restore
  - guides/storage/clone-and-convert
  - reference/cli/info
  - concepts/problems-relate-solves#single-file-graph
  - concepts/problems-relate-solves#migration-rehearsal
last_updated: 2026-11-09
---

# relate clone

The relate clone command that copies a store into a new one, between directory and .rl layouts and between codecs, with its flags, refusals and exit codes.

> Verified against relate 0.1.2. If your `relate --version` is newer, read https://relatedb.ai/docs/reference/changelog/#since-0.1.2

`relate clone SOURCE DEST` copies a [store](https://relatedb.ai/docs/reference/glossary/#store) into a new store and exits. Each side is a [directory store](https://relatedb.ai/docs/reference/glossary/#directory-store), or a [single-file store](https://relatedb.ai/docs/reference/glossary/#single-file-store) when its path ends in `.rl`, so one command copies, packs a directory into a `.rl` file, or unpacks one. The destination keeps the source's [codec](https://relatedb.ai/docs/reference/glossary/#codec) unless `--to-snapshot-format` names another. [Clone](https://relatedb.ai/docs/reference/glossary/#clone) opens the source read-only, copies the state visible when it opened, and never writes the source; it creates the destination, which must not exist yet, and prints nothing on success.

## Synopsis

```text
relate clone [--wal-dir DIR] [--to-snapshot-format F] [--markdown-body-properties LIST] SOURCE DEST
```

| Argument | Meaning                                                                                                                                                                              |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `SOURCE` | The store to copy: a directory store, or a path ending in `.rl`. Required. `:memory:` is refused                                                                                     |
| `DEST`   | The new store: a path ending in `.rl` makes a single-file store, any other path a directory store. Required. It must not exist, and its parent directory must. `:memory:` is refused |

A directory store can be cloned while another process writes it: the clone takes the state committed when it opened and does not follow later commits. A `.rl` source is refused while another process holds it for writing. The destination's write-ahead log (WAL) starts at `<DEST>/wal` for a directory destination; a `.rl` destination holds its own.

## Options

| Flag | Argument | Default | Scope | Since | Description |
| --- | --- | --- | --- | --- | --- |
| `--wal-dir` | `DIR` | `<SOURCE>/wal` | `relate clone` | — | Source WAL of a directory source; fails with a `.rl` source. |
| `--to-snapshot-format` | `parquet\|json\|markdown` | the source codec | `relate clone` | — | Destination snapshot codec (`parquet`, `json` or `markdown`); transcodes the published checkpoint. |
| `--markdown-body-properties` | `LIST` | the source's recorded configuration, else body | `relate clone` | — | Body properties of a markdown destination (`LIST` or `Label=LIST`; entries separated by `;`). |

A — under Since: the data does not record the release that added the flag.

`relate clone` takes only these three flags. A query-run flag after `clone`, such as `--read-only` or `--json`, exits 2 with `Error: unexpected argument to clone: <flag>`; `--read-only` before `clone` exits 2 with `Error: clone cannot be combined with a query or an access flag (--read-only)`.

## Layouts

Every pairing of the two durable layouts works; the in-memory store is refused on either side. One pairing depends on the codec: in relate 0.1.2 a `.rl` destination refuses markdown body properties, so a `markdown` source reaches a `.rl` path only with `--to-snapshot-format parquet` or `json` ([Codecs](#codecs)).

| Source          | Destination     | Result                                                                                                                  |
| --------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Directory store | Directory store | A copy                                                                                                                  |
| Directory store | `.rl` path      | The store packed into one file                                                                                          |
| `.rl` file      | Directory store | The file unpacked into a folder                                                                                         |
| `.rl` file      | `.rl` path      | A copy                                                                                                                  |
| `:memory:`      | Any             | Exit code 1: `Failed to clone database: storage error: clone source must be a native directory or .rl bundle path`      |
| Any             | `:memory:`      | Exit code 1: `Failed to clone database: storage error: clone destination must be a native directory or .rl bundle path` |

These examples run in a new, empty directory. This first command writes: it creates the directory store `./team` with three people, two projects and three `WORKS_ON` relationships:

```bash verify
relate --database ./team "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)"
```

The four layout pairings, then a read-only count of the relationships in each copy:

```bash verify
relate clone ./team ./team-copy
relate clone ./team ./team.rl
relate clone ./team.rl ./team-unpacked
relate clone ./team.rl ./team-copy.rl
for store in team-copy team.rl team-unpacked team-copy.rl; do
  relate --database "./$store" --read-only --mode jsonl "MATCH (:Person)-[w:WORKS_ON]->(:Project) RETURN '$store' AS store, count(w) AS works"
done
```

```text
{"store":"team-copy","works":3}
{"planCache":"miss","timings":{"elapsed_ms":0.387583,"execute_ms":0.2,"lex_parse_ms":0.030125,"lower_ms":0.045166,"parse_ms":0.11820800000000001,"plan_ms":0.059417,"result_generation_ms":0.000292,"rewrite_ms":0.008624999999999999}}
{"store":"team.rl","works":3}
{"planCache":"miss","timings":{"elapsed_ms":0.39399999999999996,"execute_ms":0.208584,"lex_parse_ms":0.03025,"lower_ms":0.04575,"parse_ms":0.116167,"plan_ms":0.060291000000000004,"result_generation_ms":0.00025,"rewrite_ms":0.007833}}
{"store":"team-unpacked","works":3}
{"planCache":"miss","timings":{"elapsed_ms":0.33675000000000005,"execute_ms":0.181292,"lex_parse_ms":0.025791,"lower_ms":0.038542,"parse_ms":0.09875,"plan_ms":0.049499999999999995,"result_generation_ms":0.000292,"rewrite_ms":0.006875}}
{"store":"team-copy.rl","works":3}
{"planCache":"miss","timings":{"elapsed_ms":0.3995,"execute_ms":0.206292,"lex_parse_ms":0.033583,"lower_ms":0.049917,"parse_ms":0.126208,"plan_ms":0.058332999999999996,"result_generation_ms":0.000292,"rewrite_ms":0.008459}}
```

## Codecs

Without `--to-snapshot-format`, the destination keeps the source's codec. With it, clone writes the state visible when it opened, which is the last checkpoint plus the WAL commits after it, in the `parquet`, `json` or `markdown` codec; the layout and the codec are chosen independently.

| Source codec | `--to-snapshot-format` | Layouts in the example                     |
| ------------ | ---------------------- | ------------------------------------------ |
| `parquet`    | `json`                 | directory to directory, `.rl` to `.rl`     |
| `parquet`    | `markdown`             | directory to directory, `.rl` to directory |
| `parquet`    | `parquet`              | directory to directory                     |
| `json`       | `parquet`              | directory to directory                     |
| `markdown`   | `parquet`              | directory to directory, directory to `.rl` |

Any other value exits 2 with `Error: invalid --to-snapshot-format: storage error: unknown snapshot codec '<value>' (expected parquet, json, markdown or rkyv)`. `rkyv` is not compiled into the release binary: `--to-snapshot-format rkyv` exits 1 with `Failed to clone database: storage error: rkyv snapshot codec is not compiled into this build (enable the "rkyv-codec" feature)`. [Storage formats](https://relatedb.ai/docs/reference/storage/formats/#codecs) describes each codec's files.

Each pairing in the table, with the codec `relate info` reports for every result:

```bash verify
relate clone --to-snapshot-format json ./team ./team-json
relate clone --to-snapshot-format markdown ./team ./team-vault
relate clone --to-snapshot-format parquet ./team ./team-parquet
relate clone --to-snapshot-format parquet ./team-json ./from-json
relate clone --to-snapshot-format parquet ./team-vault ./from-vault
relate clone --to-snapshot-format parquet ./team-vault ./team-vault.rl
relate clone --to-snapshot-format json ./team.rl ./team-json.rl
relate clone --to-snapshot-format markdown ./team.rl ./vault-from-rl
for store in team-json team-vault team-parquet from-json from-vault team-vault.rl team-json.rl vault-from-rl; do
  printf '%s: ' "$store"
  relate info --database "./$store" | grep '^codec:'
done
```

```text
team-json: codec: json
team-vault: codec: markdown
team-parquet: codec: parquet
from-json: codec: parquet
from-vault: codec: parquet
team-vault.rl: codec: parquet
team-json.rl: codec: json
vault-from-rl: codec: markdown
```

The graph survives a round trip through the text codecs:

```bash verify
relate --database ./from-vault --read-only --mode jsonl "MATCH (p:Person)-[w:WORKS_ON]->(r:Project) RETURN p.name AS person, r.name AS project, w.since AS since ORDER BY since"
```

```text
{"person":"Grace","project":"opencypher-tck","since":2022}
{"person":"Grace","project":"relate","since":2023}
{"person":"Ada","project":"relate","since":2024}
{"planCache":"miss","timings":{"elapsed_ms":0.579875,"execute_ms":0.39808299999999996,"lex_parse_ms":0.030583000000000003,"lower_ms":0.044875,"parse_ms":0.115042,"plan_ms":0.058415999999999996,"result_generation_ms":0.000417,"rewrite_ms":0.008333}}
```

### Markdown into a `.rl` file

In relate 0.1.2 a `.rl` destination refuses markdown body properties, whether they come from `--markdown-body-properties` or from the configuration a `markdown` source records. Cloning a `markdown` store into a `.rl` path therefore needs `--to-snapshot-format parquet` or `json`; without it, or with `--to-snapshot-format markdown`, the clone exits 1 and creates nothing. The message names `parquet` whatever codec the command asked for:

```bash verify
relate clone ./team-vault ./vault-kept.rl
echo "exit=$?"
relate clone --to-snapshot-format markdown ./team-vault ./vault-md.rl
echo "exit=$?"
```

```text
Failed to clone database: semantic error: markdown body properties are set but the store's snapshot codec is parquet, not markdown; the configuration would be ignored
exit=1
Failed to clone database: semantic error: markdown body properties are set but the store's snapshot codec is parquet, not markdown; the configuration would be ignored
exit=1
```

A `parquet` or `json` source with no body properties clones into a `markdown` `.rl` file: `relate clone --to-snapshot-format markdown ./team.rl ./team-md.rl` succeeds, and `relate info` reports `codec: markdown` for it. A `markdown` store clones into a directory store with any codec.

### Markdown body properties

`--markdown-body-properties` names the properties a `markdown` destination writes as each note's body instead of its frontmatter: a comma-separated list for every label, or `Label=LIST` for one label, with several entries separated by `;` (`Person=role,bio;Project=language`). The first listed property is written as the bare body and the rest as `##` sections. Without the flag, the destination uses the source's recorded configuration, else the single property `body`. On a directory destination whose codec is not `markdown`, it exits 1 with `Failed to clone database: semantic error: markdown body properties are set but the store's snapshot codec is parquet, not markdown; the configuration would be ignored` (the codec named is the destination's).

```bash verify
relate clone --to-snapshot-format markdown --markdown-body-properties 'Person=role' ./team ./team-notes
cat team-notes/Person/Ada.md
```

```text
---
type: Person
name: Ada
KNOWS:
  - "[[Person/Grace]]"
WORKS_ON:
  - since: 2024
    target: "[[Project/relate]]"
---

engineer
```

## WAL directory

`--wal-dir DIR` names the source's WAL when it is not at `<SOURCE>/wal`. It applies to a directory source only; with a `.rl` source, which holds its own WAL, it exits 1 with `Failed to clone database: storage error: wal_dir is not supported for .rl single-file databases (ADR-0074)`. It does not move the destination's WAL.

## What clone refuses

| Input                                                                                                                                                 | Exit code | Message                                                                                                                                                                  |
| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DEST` exists                                                                                                                                         | 1         | `Failed to clone database: storage error: clone destination already exists`                                                                                              |
| `DEST`'s parent directory does not exist                                                                                                              | 1         | `Failed to clone database: storage error: clone destination parent does not exist: <path>`                                                                               |
| A directory `SOURCE` that does not exist                                                                                                              | 1         | `Failed to clone database: storage error: read-only open requires an existing database at <path>`                                                                        |
| A `.rl` `SOURCE` that does not exist                                                                                                                  | 1         | `Failed to clone database: storage error: database not found: <path>`                                                                                                    |
| A `.rl` `SOURCE` another process holds for writing                                                                                                    | 1         | `Failed to clone database: storage locked: <path>`                                                                                                                       |
| `:memory:` on either side                                                                                                                             | 1         | `clone source must be a native directory or .rl bundle path`, or `clone destination …`, after `Failed to clone database: storage error: `                                |
| A `.rl` `DEST` with markdown body properties: a `markdown` `SOURCE` without `--to-snapshot-format parquet` or `json`, or `--markdown-body-properties` | 1         | `Failed to clone database: semantic error: markdown body properties are set but the store's snapshot codec is parquet, not markdown; the configuration would be ignored` |
| `--wal-dir` with a `.rl` source                                                                                                                       | 1         | `Failed to clone database: storage error: wal_dir is not supported for .rl single-file databases (ADR-0074)`                                                             |
| Fewer than two paths                                                                                                                                  | 2         | `Error: clone requires SOURCE and DEST`                                                                                                                                  |
| A third path, or a flag clone does not take                                                                                                           | 2         | `Error: unexpected argument to clone: <argument>`                                                                                                                        |

A runtime refusal (exit code 1) prints one line on stderr and no error object. A usage error (exit code 2) prints the error line, the usage line and `Run 'relate clone --help' for more information.`

## Errors and exit codes

| Exit code                                                                 | Meaning for `relate clone`                                                                       |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [0](https://relatedb.ai/docs/reference/cli/exit-codes-and-errors/#exit-0) | The destination was created; nothing is printed                                                  |
| [1](https://relatedb.ai/docs/reference/cli/exit-codes-and-errors/#exit-1) | The copy did not run or did not finish: a refusal in the table, or a storage or I/O error        |
| [2](https://relatedb.ai/docs/reference/cli/exit-codes-and-errors/#exit-2) | Usage error: a missing or extra argument, an unknown flag, or a bad `--to-snapshot-format` value |

## Examples

An existing destination is never overwritten:

```bash verify
relate clone ./team ./team-copy
echo "exit=$?"
```

```text
Failed to clone database: storage error: clone destination already exists
exit=1
```

## See also

- [Storage formats](https://relatedb.ai/docs/reference/storage/formats/): the layouts and codecs clone converts between
- [Back up and restore a store](https://relatedb.ai/docs/guides/storage/backup-and-restore/): clone as a backup that opens
- [relate info](https://relatedb.ai/docs/reference/cli/info/): the layout, codec and counts of a clone, read without opening it
- [CLI flags](https://relatedb.ai/docs/reference/cli/flags/#relate-clone): the clone flags beside every other command's

## Terms used on this page

- **store**: A relate database: a directory, a single `.rl` file, or `:memory:`, opened with `--database`.
- **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`.
- **single-file store**: A store kept in one `.rl` file that holds the snapshot and the WAL together; the layout for a `--database` path ending in `.rl`.
- **codec**: The on-disk encoding of a store's snapshot: Parquet (the default), JSON or markdown, fixed when the store is created.
- **clone**: `relate clone`: the command that copies a store into a new one, optionally in another codec, reading the source without writing it.
