# instance

Reference for surrealctl instance — creating, scaling, pausing and deleting instances, reading logs, metrics and endpoints, minting tokens, and managing capabilities and backups.

`surrealctl instance` manages instances: the databases themselves. It is the largest group in the CLI, and covers provisioning, scaling, observability, credentials, capabilities and backups.

<Synopsis>
surrealctl instance <COMMAND> [OPTIONS]
surrealctl instances <COMMAND> [OPTIONS]
</Synopsis>

| Verb | Purpose | Alias |
| --- | --- | --- |
| [`list`](#instance-list) | List the instances in an organisation | `ls` |
| [`get`](#instance-get) | Show one instance | |
| [`create`](#instance-create) | Create an instance | |
| [`update`](#instance-update) | Change an instance's type, size, or version | |
| [`delete`](#instance-delete) | Delete an instance and everything in it | `rm` |
| [`pause`](#instance-pause) | Pause a running instance | |
| [`resume`](#instance-resume) | Resume a paused instance | |
| [`watch`](#instance-watch) | Watch an operation that was started elsewhere | |
| [`status`](#instance-status) | Show an instance's deployment phase and restorable snapshots | |
| [`endpoint`](#instance-endpoint) | Print the endpoint a client connects to | |
| [`token`](#instance-token) | Mint a database token for an instance | |
| [`jwks`](#instance-jwks) | Fetch the key set that verifies an instance's tokens | |
| [`sql`](#instance-sql) | Open a SurrealQL session against an instance | |
| [`import`](#instance-import) | Import a file into an instance | |
| [`export`](#instance-export) | Export an instance to a file | |
| [`metrics`](#instance-metrics) | Show an instance's resource metrics | |
| [`logs`](#instance-logs) | Show an instance's logs | |
| [`usage`](#instance-usage) | Show what an instance has consumed | |
| [`estimate`](#instance-estimate) | Estimate what an instance would cost | |
| [`capabilities get`](#instance-capabilities-get) | Show an instance's capability configuration | |
| [`capabilities set`](#instance-capabilities-set) | Change an instance's capability configuration | |
| [`backup list`](#instance-backup-list) | List the snapshots an instance can be restored from | `ls` |
| [`backup create`](#instance-backup-create) | Take a backup of an instance now | |
| [`backup policy get`](#instance-backup-policy-get) | Show the backup retention policy | |
| [`backup policy set`](#instance-backup-policy-set) | Change the backup retention policy | |

## Naming an instance

Four spellings are accepted: the id, the slug, the name, or `org/name`. Only a bare id avoids a lookup against the organisation. A slug always contains a hyphen, so it can never be mistaken for an id.

```bash
surrealctl instance get production
surrealctl instance get production-6xk2
surrealctl instance get acme/production
surrealctl instance get 67upif0m8sh1cn1p2c8t
```

Omit the reference entirely and, on a terminal, you get a picker. Elsewhere it is a usage error, exit `2`, listing what was available:

```text
No instance was given and this session cannot prompt.
Name one, or pass --org to change which organization is searched.

Available:
  production
  staging
```

There is deliberately no `instance use`. A sticky implicit target is fine for a noun whose verbs are mostly reads, and wrong for one whose verbs include `delete`.

## surrealctl instance list {#instance-list}

List the instances in an organisation.

<Synopsis>
surrealctl instance list [OPTIONS]
</Synopsis>

This command takes no positional argument, deliberately: a positional here would read as an *instance*. The organisation comes from `--org` and the [precedence chain](/docs/reference/cli/surrealctl/global-flags.md#the-precedence-chain).

Accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags) and nothing else. Column ids are `name`, `state`, `type`, `version`, `region`, `compute_units` and `storage`, with `id`, `slug`, `host`, `access_type` and `organization_id` under `--wide`.

```bash
surrealctl instance list
```

```text title="Output"
NAME        STATE   TYPE          VERSION  REGION     UNITS  STORAGE
production  ready   production-2  3.2.4    aws-euw1       4   100 GB
staging     paused  shared-1      3.2.4    aws-euw1       1    10 GB
```

```bash title="Ready instances only, as names"
surrealctl instance list --json | jq -r '.[] | select(.state == "ready") | .name'
```

## surrealctl instance get {#instance-get}

Show one instance.

<Synopsis>
surrealctl instance get [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

This command has no options of its own.

```bash
surrealctl instance get production
```

```bash title="One field, for a script"
surrealctl instance get production --json | jq -r .state
```

## surrealctl instance create {#instance-create}

Create an instance.

<Synopsis>
surrealctl instance create [OPTIONS] --type <SLUG> --region <SLUG> <NAME>
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "<NAME>",
            "required": true,
            "description": "A name for the instance. Between 1 and 30 characters."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--type",
            "value": "<SLUG>",
            "required": true,
            "description": "The instance type, by slug. See `surrealctl catalog instance-types`."
        },
        {
            "name": "--region",
            "value": "<SLUG>",
            "required": true,
            "description": "The region to deploy into, by slug. See `surrealctl catalog regions`."
        },
        {
            "name": "--version",
            "value": "<VERSION>",
            "description": "The SurrealDB version to run. Defaults to the platform's current one."
        },
        {
            "name": "--compute-units",
            "value": "<N>",
            "description": "How many compute units to run, for the types that scale. Minimum 1."
        },
        {
            "name": "--storage",
            "value": "<GB>",
            "description": "Storage to allocate, in gigabytes. Minimum 1."
        },
        {
            "name": "--access-type",
            "value": "<ACCESS>",
            "description": "How the instance may be reached: `public`, `private` or `dual`."
        },
        {
            "name": "--restore-from",
            "value": "<INSTANCE/SNAPSHOT>",
            "description": "Restore from a snapshot, as `<instance>/<snapshot>`."
        },
        {
            "name": "--wait",
            "description": "Wait for the instance to become ready. On by default."
        },
        {
            "name": "--no-wait",
            "description": "Return as soon as the API accepts the request."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to wait before giving up."
        }
    ]}
/>

| `--access-type` value | Meaning |
| --- | --- |
| `public` | Reachable over the public internet. The API's own default |
| `private` | Reachable over PrivateLink only. Needs PrivateLink on the organisation |
| `dual` | Reachable both ways |

```bash title="Create and wait for it to be ready"
surrealctl instance create api --type shared-1 --region aws-euw1
```

```bash title="A production instance with room to grow"
surrealctl instance create production \
    --type production-2 \
    --region aws-euw1 \
    --compute-units 4 \
    --storage 100
```

```bash title="Clone from a snapshot"
surrealctl instance create staging \
    --type shared-1 \
    --region aws-euw1 \
    --restore-from production/rsnapshot-20260811-150405
```

With the wait, the command reports progress and then emits a fresh detail view. With `--no-wait` it emits the accepted request and hints at `surrealctl instance watch <name>`.

**Refusals**, all exit `2` and all before any request:

- A name outside 1 to 30 characters, with the length it counted.
- `--compute-units` below 1, or `--storage` below 1.
- A malformed `--restore-from`, which is split on the last `/`:

```text
`prod-snap-1` is not a snapshot reference. Use <instance>/<snapshot>, for example
production/rsnapshot-20250128-150405.
Run `surrealctl instance status <instance>` to list the snapshots an instance can be restored from.
```

> [!WARNING]
> The create route accepts no idempotency key, so a retried create is a second instance and a second bill. `surrealctl` never retries it after a `502` for exactly that reason. If a create times out, run [`instance list`](#instance-list) before running it again.

## surrealctl instance update {#instance-update}

Change an instance's type, size, or version.

<Synopsis>
surrealctl instance update [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--type",
            "value": "<SLUG>",
            "description": "Move to this instance type, by slug."
        },
        {
            "name": "--compute-units",
            "value": "<N>",
            "description": "Scale to this many compute units. Minimum 1."
        },
        {
            "name": "--storage",
            "value": "<GB>",
            "description": "Grow storage to this many gigabytes. Minimum 1."
        },
        {
            "name": "--version",
            "value": "<VERSION>",
            "description": "Upgrade to this SurrealDB version."
        },
        {
            "name": "--access-type",
            "value": "<ACCESS>",
            "description": "Change how the instance may be reached: `public`, `private` or `dual`."
        },
        {
            "name": "--wait",
            "description": "Wait for the instance to become ready again. On by default."
        },
        {
            "name": "--no-wait",
            "description": "Return as soon as the API accepts the last change."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to wait before giving up."
        }
    ]}
/>

There is no single update route on the API — each field has its own — so one invocation is several requests. They are applied in a fixed order and stop at the first failure:

1. `--type`
2. `--compute-units`
3. `--storage`
4. `--version`
5. `--access-type`

> [!IMPORTANT]
> Every one of these restarts the instance. A single `instance update` that changes three fields restarts it once per field, in the order above.

```bash title="Scale up"
surrealctl instance update production --compute-units 8
```

```bash title="Upgrade the SurrealDB version"
surrealctl instance update production --version 3.2.4
```

```bash title="Change type and grow storage in one go"
surrealctl instance update production --type production-4 --storage 250
```

**Refusals**, all exit `2`:

- No flags at all:

```text
Nothing to update. Pass at least one of --type, --compute-units, --storage, --version, or --access-type.
```

- `--compute-units` or `--storage` below 1.
- A storage cool-off still in force, naming the interval and, when known, when storage was last changed.
- `--compute-units` outside the current type's range, when `--type` is not also being changed:

```text
`shared-1` accepts 1–2 compute units; 8 is outside that.
```

## surrealctl instance delete {#instance-delete}

Delete an instance and everything in it.

<Synopsis>
surrealctl instance delete [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--force",
            "description": "Delete without confirming."
        },
        {
            "name": "--wait",
            "description": "Wait for the instance to disappear. On by default."
        },
        {
            "name": "--no-wait",
            "description": "Return as soon as the API accepts the request."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to wait before giving up."
        }
    ]}
/>

```bash title="Delete, with a confirmation"
surrealctl instance delete staging
```

```bash title="Delete from a teardown script"
surrealctl instance delete staging --force --json
```

The confirmation names the instance, its slug and its region, so the wrong terminal tab is caught before the request. Declining prints `Nothing was deleted.` and exits `0` with no document. In a non-interactive session without `--force` or `--yes`, it exits `2` having sent nothing.

The delete route answers with no body, so the emitted document is synthesised:

```json title="Output"
{
  "id": "67upif0m8sh1cn1p2c8t",
  "name": "staging",
  "slug": "staging-4jd1",
  "state": "deleted"
}
```

While waiting, a `404` is the success condition — there is nothing left to fetch.

## surrealctl instance pause {#instance-pause}

Pause a running instance.

<Synopsis>
surrealctl instance pause [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--wait",
            "description": "Wait for the instance to pause. On by default."
        },
        {
            "name": "--no-wait",
            "description": "Return as soon as the API accepts the request."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to wait before giving up."
        }
    ]}
/>

```bash
surrealctl instance pause staging
```

Pausing something already paused prints a note and still emits a document, exit `0`. The shape of the answer does not change with remote state, so a script does not need to know which case it hit.

## surrealctl instance resume {#instance-resume}

Resume a paused instance.

<Synopsis>
surrealctl instance resume [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--wait",
            "description": "Wait for the instance to become ready. On by default."
        },
        {
            "name": "--no-wait",
            "description": "Return as soon as the API accepts the request."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to wait before giving up."
        }
    ]}
/>

```bash
surrealctl instance resume staging
```

Resuming something already ready behaves like pausing something already paused: a note, a document, exit `0`.

## surrealctl instance watch {#instance-watch}

Watch an operation that was started elsewhere.

<Synopsis>
surrealctl instance watch [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--until",
            "value": "<STATE>",
            "default": "ready",
            "description": "The state to wait for: `ready`, `paused` or `deleted`."
        },
        {
            "name": "--wait-timeout",
            "value": "<DURATION>",
            "default": "15m",
            "description": "How long to watch before giving up."
        }
    ]}
/>

There is no `--wait` or `--no-wait` here, because a watch is nothing but a wait.

| `--until` value | Finishes when |
| --- | --- |
| `ready` | The instance is running and healthy |
| `paused` | The instance is deliberately stopped |
| `deleted` | The instance is gone — a `404` while polling is what finishes this one |

```bash title="Pick up a create started in an earlier CI job"
surrealctl instance watch api
```

```bash title="Wait for a pause to complete"
surrealctl instance watch staging --until paused
```

> [!NOTE]
> This is the one command where `--json` writes to stdout continuously. The transitions *are* the answer, so the newline-delimited stream goes to stdout and nothing else is emitted. In text mode the run ends with a fresh detail view, except under `--until deleted`, where there is nothing left to fetch.

```bash title="Follow the transitions as they happen"
surrealctl instance watch api --json | jq -r '.event + " " + (.state // "")'
```

## surrealctl instance status {#instance-status}

Show an instance's deployment phase and restorable snapshots.

<Synopsis>
surrealctl instance status [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

Also accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags), which arrange the snapshot table. Column ids are `snapshot_id`, `started_at`, `tiers` and `on_demand`, with `valid_versions` under `--wide`.

```bash
surrealctl instance status production
```

The answer is one composite document: a phase, then the snapshots the instance can be restored from. In plain mode the phase is written as `phase<tab><Phase>` before the table, so `grep ^phase` works the same way it does on [`instance get`](#instance-get). An instance with no restorable snapshots gets a note on stderr rather than an empty table with no explanation.

Snapshot ids from here are what [`instance create --restore-from`](#instance-create) expects.

## surrealctl instance endpoint {#instance-endpoint}

Print the endpoint a client connects to.

<Synopsis>
surrealctl instance endpoint [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

This command has no options of its own.

The output is the bare endpoint plus a newline, byte-identical in rich and plain output, so `$(…)` captures exactly the value with no label and no styling.

```bash
ENDPOINT=$(surrealctl instance endpoint production)
surreal sql --endpoint "$ENDPOINT" --namespace app --database main
```

```bash title="Under --json, the hosts come too"
surrealctl instance endpoint production --json
```

```json title="Output"
{
  "endpoint": "wss://production-6xk2.aws-euw1.surreal.cloud",
  "host": "production-6xk2.aws-euw1.surreal.cloud",
  "private_host": null,
  "access_type": "public"
}
```

A private-only instance produces a warning on stderr rather than a refusal — the endpoint is still correct, it is simply not reachable from where you are.

## surrealctl instance token {#instance-token}

Mint a database token for an instance.

<Synopsis>
surrealctl instance token [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--reveal",
            "description": "Print the token even when stdout is a terminal."
        }
    ]}
/>

This is a *database* token — the credential a SurrealDB client authenticates with. It is not a [personal access token](/docs/reference/cli/surrealctl/commands/token.md), which authenticates against the control plane.

```bash title="Copy it to the clipboard"
surrealctl instance token production | pbcopy
```

```bash title="Use it with the surreal CLI"
SURREAL_TOKEN=$(surrealctl instance token production) \
    surreal sql --endpoint "$(surrealctl instance endpoint production)" --namespace app --database main
```

**Refusals.** Printing a credential into a terminal's scrollback is refused, exit `2`, and the check happens *before* the token is minted — so a forgotten `--reveal` never costs a credential nobody can recover:

```text
Refusing to print a database token to a terminal, where it would stay in your scrollback.
Pipe it:  surrealctl instance token production | pbcopy
Or pass --reveal if you meant to see it.
```

Under `--json` the answer is a one-field document carrying the instance id and the token.

## surrealctl instance jwks {#instance-jwks}

Fetch the key set that verifies an instance's tokens.

<Synopsis>
surrealctl instance jwks [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug, name, or org/name. Omit to choose interactively."
        }
    ]}
/>

Also accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags). Column ids are the JWK member names — `kid`, `kty`, `alg` and `use`, with `crv` under `--wide` — so a member the key type does not carry renders as missing rather than empty.

```bash title="Inspect the keys"
surrealctl instance jwks production
```

```bash title="Pipe the whole key set into a verifier"
surrealctl instance jwks production --json > jwks.json
```

Under `--json` the whole key set is emitted, `keys` wrapper included, so it can be handed straight to a JWT library.

## surrealctl instance sql {#instance-sql}

Open a SurrealQL session against an instance.

<Synopsis>
surrealctl instance sql [OPTIONS] [INSTANCE] [-- <ARGS>...]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        },
        {
            "name": "[ARGS]...",
            "description": "Arguments for `surreal sql`, after a `--` separator."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--namespace",
            "value": "<NS>",
            "description": "The namespace to open."
        },
        {
            "name": "--database",
            "value": "<DB>",
            "description": "The database to open."
        }
    ]}
/>

This command does not speak SurrealQL. It resolves the instance, mints a database token, and becomes [`surreal sql`](/docs/reference/cli/surrealdb-cli/commands/sql.md). Everything after `--` is forwarded to that command verbatim, because the sibling's flag surface is large and moves independently.

```bash title="Open a shell"
surrealctl instance sql production --namespace app --database main
```

```bash title="Pass flags through to surreal sql"
surrealctl instance sql production -- --ns app --db main --pretty
```

```bash title="Run a query from a pipeline"
echo "SELECT count() FROM person GROUP ALL;" \
    | surrealctl instance sql production --namespace app --database main
```

`--namespace` and `--database` are optional here, because `surreal sql` accepts a session without them. See [the `surreal` handoff](/docs/manage/surrealctl/install.md#the-surreal-handoff) for how the binary is located and what is passed in the child's environment.

**Warnings**, neither of which stops the handoff: a private-only instance, and an instance that is not in a ready phase.

## surrealctl instance import {#instance-import}

Import a file into an instance.

<Synopsis>
surrealctl instance import [OPTIONS] [INSTANCE] [-- <ARGS>...]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        },
        {
            "name": "[ARGS]...",
            "description": "Arguments for `surreal import`, after a `--` separator. The file to load goes here."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--namespace",
            "value": "<NS>",
            "required": true,
            "description": "The namespace to import into."
        },
        {
            "name": "--database",
            "value": "<DB>",
            "required": true,
            "description": "The database to import into."
        }
    ]}
/>

```bash
surrealctl instance import production --namespace app --database main -- ./seed.surql
```

**Refusals.** `surreal import` requires both a namespace and a database, so this command does too. The check fires before a token is minted:

```text
`surrealctl instance import` needs both --namespace and --database; `surreal import` requires them.
```

See [`surreal import`](/docs/reference/cli/surrealdb-cli/commands/import.md) for the flags available after the `--`.

## surrealctl instance export {#instance-export}

Export an instance to a file.

<Synopsis>
surrealctl instance export [OPTIONS] [INSTANCE] [-- <ARGS>...]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        },
        {
            "name": "[ARGS]...",
            "description": "Arguments for `surreal export`, after a `--` separator. The destination goes here, or `-` for stdout."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--namespace",
            "value": "<NS>",
            "required": true,
            "description": "The namespace to export from."
        },
        {
            "name": "--database",
            "value": "<DB>",
            "required": true,
            "description": "The database to export from."
        }
    ]}
/>

```bash title="Export to a file"
surrealctl instance export production --namespace app --database main -- ./backup.surql
```

```bash title="Export to stdout and compress"
surrealctl instance export production --namespace app --database main -- - | gzip > backup.surql.gz
```

Like `import`, this refuses a missing namespace or database before minting anything. See [`surreal export`](/docs/reference/cli/surrealdb-cli/commands/export.md) for the flags available after the `--`.

For a managed snapshot rather than a SurrealQL dump, use [`instance backup create`](#instance-backup-create).

## surrealctl instance metrics {#instance-metrics}

Show an instance's resource metrics.

<Synopsis>
surrealctl instance metrics [OPTIONS] --metric <METRIC> [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--metric",
            "value": "<METRIC>",
            "required": true,
            "description": "Which metric to read, such as `cpu`, `memory` or `disk`."
        },
        {
            "name": "--from",
            "value": "<TIME>",
            "description": "Start of the window, as an RFC 3339 timestamp."
        },
        {
            "name": "--to",
            "value": "<TIME>",
            "description": "End of the window, as an RFC 3339 timestamp."
        },
        {
            "name": "--samples",
            "description": "Show every sample instead of one summary per series."
        }
    ]}
/>

Also accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags). Summary rows carry `series`, `last`, `min`, `mean`, `max` and `unit`, with `samples` and `gaps` under `--wide`; sample rows carry `timestamp`, `series` and `value`, with `unit` under `--wide`.

`--metric` is a free-form string rather than a fixed set, because the platform's metric vocabulary is not published anywhere the CLI can read it.

```bash title="A summary per series"
surrealctl instance metrics production --metric cpu
```

```bash title="Every sample over a window"
surrealctl instance metrics production \
    --metric memory \
    --from 2026-08-11T10:00:00Z \
    --to 2026-08-11T12:00:00Z \
    --samples
```

Timestamps are validated locally and forwarded byte-for-byte, never reformatted:

```text
Ensure `11-08-2026` is an RFC3339 timestamp, such as 2026-08-11T10:00:00Z
```

`--samples` chooses a table, not a payload: `--json` carries the whole document either way. A note on stderr states the metric, its unit and the window.

## surrealctl instance logs {#instance-logs}

Show an instance's logs.

<Synopsis>
surrealctl instance logs [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--from",
            "value": "<TIME>",
            "description": "Start of the window, as an RFC 3339 timestamp."
        },
        {
            "name": "--to",
            "value": "<TIME>",
            "description": "End of the window, as an RFC 3339 timestamp. Conflicts with `--follow`."
        },
        {
            "name": "--level",
            "value": "<LEVELS>",
            "description": "Show only these levels, comma-separated. Filtered locally; the API has no level parameter."
        },
        {
            "name": "--follow",
            "short": "-f",
            "description": "Keep printing new lines. There is no streaming endpoint, so this polls."
        }
    ]}
/>

Also accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags). Column ids are `timestamp`, `level` and `message`, with `pod` under `--wide`.

```bash title="Recent lines"
surrealctl instance logs production
```

```bash title="Errors and warnings only"
surrealctl instance logs production --level error,warn
```

```bash title="Follow, and hand each line to jq"
surrealctl instance logs production --follow --json | jq -r '.timestamp + " " + .message'
```

`--level` is a display filter applied on this side, and a note reports how many lines were hidden. `--json` still carries every line the API sent. `--limit` takes from the start of the window, matching its meaning elsewhere.

`--follow` polls with a moving start time at a fixed five-second interval — there is no streaming endpoint and no interval flag. Under `--follow --json`, each new line is written as newline-delimited JSON on stdout; in text mode a table is printed per batch, with the header only on the first.

## surrealctl instance usage {#instance-usage}

Show what an instance has consumed.

<Synopsis>
surrealctl instance usage [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

Accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags) and nothing else — this route takes no query parameters at all. Column ids are `instance_id`, `metric_type`, `compute_hours`, `disk_used_bytes`, `period_start` and `period_end`, with `instance_type` and `source` under `--wide`.

```bash
surrealctl instance usage production
```

For every instance in the organisation at once, use [`org usage`](/docs/reference/cli/surrealctl/commands/org.md#org-usage).

## surrealctl instance estimate {#instance-estimate}

Estimate what an instance would cost.

<Synopsis>
surrealctl instance estimate [OPTIONS] --type <SLUG> --region <REGION>
</Synopsis>

This command takes no positional argument: it prices a hypothetical instance, so there is nothing to name.

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--type",
            "value": "<SLUG>",
            "required": true,
            "description": "The instance type to price, by slug."
        },
        {
            "name": "--region",
            "value": "<REGION>",
            "required": true,
            "description": "The region to price it in."
        },
        {
            "name": "--units",
            "value": "<N>",
            "description": "How many compute units. Defaults to the type's own. Minimum 1."
        },
        {
            "name": "--storage",
            "value": "<GB>",
            "description": "How much storage, in gigabytes. Defaults to the type's own. Minimum 1."
        }
    ]}
/>

```bash title="Price a change before making it"
surrealctl instance estimate --type production-4 --region aws-euw1 --units 8 --storage 250
```

Flags you omit are left out of the request rather than sent as null, so the platform's own defaults for that type apply.

**Refusals**, exit `2`:

```text
An instance has at least 1 compute unit; 0 was given.
An instance has at least 1GB of storage; 0 was given.
```

This is the one place the API does not use integer minor units — the cost is a number in a named currency — and `--json` keeps the raw value.

## surrealctl instance capabilities get {#instance-capabilities-get}

Show an instance's capability configuration.

<Synopsis>
surrealctl instance capabilities get [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

This command has no options of its own.

```bash
surrealctl instance capabilities get production
```

Under `--json` the nested capabilities object is emitted, not the whole instance — so it can be diffed against another instance directly.

```bash title="Compare two instances"
diff <(surrealctl instance capabilities get staging --json) \
     <(surrealctl instance capabilities get production --json)
```

## surrealctl instance capabilities set {#instance-capabilities-set}

Change an instance's capability configuration.

<Synopsis>
surrealctl instance capabilities set [OPTIONS] [INSTANCE]
</Synopsis>

The capabilities route is a full replacement, so this command reads the current configuration, applies the flags given here, shows what would change, and asks before writing. A list flag **replaces** that list rather than adding to it, and anything not named is left exactly as it is — including capabilities this build does not know about.

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--allow-scripting",
            "description": "Allow embedded scripting functions. Conflicts with `--deny-scripting`."
        },
        {
            "name": "--deny-scripting",
            "description": "Refuse embedded scripting functions."
        },
        {
            "name": "--allow-guests",
            "description": "Allow unauthenticated guest access. Conflicts with `--deny-guests`."
        },
        {
            "name": "--deny-guests",
            "description": "Refuse unauthenticated guest access."
        },
        {
            "name": "--allow-experimental",
            "value": "<NAMES>",
            "description": "Experimental features to allow, comma-separated."
        },
        {
            "name": "--deny-experimental",
            "value": "<NAMES>",
            "description": "Experimental features to deny, comma-separated."
        },
        {
            "name": "--allow-arbitrary-query",
            "value": "<TARGETS>",
            "description": "Arbitrary-query targets to allow, comma-separated."
        },
        {
            "name": "--deny-arbitrary-query",
            "value": "<TARGETS>",
            "description": "Arbitrary-query targets to deny, comma-separated."
        },
        {
            "name": "--allow-eval-query",
            "value": "<TARGETS>",
            "description": "Eval-query targets to allow, comma-separated."
        },
        {
            "name": "--deny-eval-query",
            "value": "<TARGETS>",
            "description": "Eval-query targets to deny, comma-separated."
        },
        {
            "name": "--allow-rpc",
            "value": "<METHODS>",
            "description": "RPC methods to allow, comma-separated."
        },
        {
            "name": "--deny-rpc",
            "value": "<METHODS>",
            "description": "RPC methods to deny, comma-separated."
        },
        {
            "name": "--allow-http",
            "value": "<ENDPOINTS>",
            "description": "HTTP endpoints to allow, comma-separated."
        },
        {
            "name": "--deny-http",
            "value": "<ENDPOINTS>",
            "description": "HTTP endpoints to deny, comma-separated."
        },
        {
            "name": "--allow-net",
            "value": "<TARGETS>",
            "description": "Networks to allow, comma-separated."
        },
        {
            "name": "--deny-net",
            "value": "<TARGETS>",
            "description": "Networks to deny, comma-separated."
        },
        {
            "name": "--allow-funcs",
            "value": "<FUNCTIONS>",
            "description": "Functions to allow, comma-separated."
        },
        {
            "name": "--deny-funcs",
            "value": "<FUNCTIONS>",
            "description": "Functions to deny, comma-separated."
        },
        {
            "name": "--force",
            "description": "Replace the capabilities without confirming."
        }
    ]}
/>

```bash title="Turn scripting off"
surrealctl instance capabilities set production --deny-scripting
```

```bash title="Replace the allowed function list"
surrealctl instance capabilities set production --allow-funcs "array,string,time"
```

```bash title="Deny outbound HTTP from a script"
surrealctl instance capabilities set production --deny-funcs "http::*" --force
```

The diff is printed on stderr in **every** mode, `--json` included, then confirmed unless `--force` is given. Declining prints `Nothing was changed.` and exits `0`.

**Refusals and short-circuits.** No flags at all is a usage error, exit `2`, before any request:

```text
Nothing to set. Pass at least one capability flag, such as --allow-scripting or --deny-funcs http::*.
Run `surrealctl instance capabilities get` to see the current configuration.
```

Flags that would change nothing produce a note and exit `0` without a write:

```text
`production` already has those capabilities. Nothing was changed.
```

## surrealctl instance backup list {#instance-backup-list}

List the snapshots an instance can be restored from.

<Synopsis>
surrealctl instance backup list [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

Accepts the [list presentation flags](/docs/reference/cli/surrealctl/output-and-exit-codes.md#list-presentation-flags) and nothing else. Column ids are `snapshot_id`, `started_at`, `tiers` and `on_demand`, with `valid_versions` under `--wide`.

```bash
surrealctl instance backup list production
```

```bash title="The newest snapshot id"
surrealctl instance backup list production --sort started_at --reverse --limit 1 \
    --columns snapshot_id --no-header
```

There is no backup collection route on the API, so this reads the snapshots off the instance's status route. `--json` carries the snapshot array rather than the whole status document. [`instance status`](#instance-status) shows the same snapshots alongside the deployment phase.

## surrealctl instance backup create {#instance-backup-create}

Take a backup of an instance now.

<Synopsis>
surrealctl instance backup create [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

This command has no options of its own, and carries no `--wait` or `--no-wait`.

```bash
surrealctl instance backup create production
```

The route answers with no body, so the document is synthesised:

```json title="Output"
{
  "instance_id": "67upif0m8sh1cn1p2c8t",
  "status": "accepted"
}
```

A replayed request is a second snapshot, so this call is never retried automatically. Requesting a backup while one is already queued is reported as a conflict, exit `6`, rather than as a rate limit — the condition is "one is already running", not "you are asking too often".

Poll [`instance backup list`](#instance-backup-list) to see the snapshot appear.

## surrealctl instance backup policy get {#instance-backup-policy-get}

Show the backup retention policy.

<Synopsis>
surrealctl instance backup policy get [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

This command has no options of its own.

```bash
surrealctl instance backup policy get production
```

The answer reports each retention tier, how often snapshots are taken, and which tiers this organisation's plan allows you to change — which is what [`backup policy set`](#instance-backup-policy-set) will accept.

## surrealctl instance backup policy set {#instance-backup-policy-set}

Change the backup retention policy.

<Synopsis>
surrealctl instance backup policy set [OPTIONS] [INSTANCE]
</Synopsis>

<OptionsTable
    title="Arguments"
    options={[
        {
            "name": "[INSTANCE]",
            "description": "The instance, by id, slug or name. Defaults to the resolved one."
        }
    ]}
/>

<OptionsTable
    title="Options"
    options={[
        {
            "name": "--daily",
            "value": "<DAYS>",
            "description": "How many days of daily snapshots to keep, or the literal `default`."
        },
        {
            "name": "--weekly",
            "value": "<WEEKS>",
            "description": "How many weeks of weekly snapshots to keep, or the literal `default`."
        },
        {
            "name": "--monthly",
            "value": "<MONTHS>",
            "description": "How many months of monthly snapshots to keep, or the literal `default`."
        },
        {
            "name": "--frequency-hours",
            "value": "<HOURS>",
            "description": "How often to take a snapshot, in hours. Checked against the allow-list this organisation's plan publishes, not against a range."
        },
        {
            "name": "--force",
            "description": "Change the policy without confirming."
        }
    ]}
/>

The three retention flags also accept the literal `default`, which restores this organisation's own value for that tier. `--frequency-hours` has no `default` form, because the platform gives it no resettable value.

`--frequency-hours` is an **allow-list**, not a range: the plan publishes the intervals it offers, and a value sitting between two of them is refused rather than rounded. Run [`backup policy get`](#instance-backup-policy-get) to see which intervals this plan offers.

```bash title="Keep a fortnight of dailies"
surrealctl instance backup policy set production --daily 14
```

```bash title="Snapshot every six hours"
surrealctl instance backup policy set production --frequency-hours 6
```

```bash title="Reset the monthly tier to the organisation's own value"
surrealctl instance backup policy set production --monthly default
```

**Confirmation.** Only a *reduction* asks. Lengthening a retention cannot lose a snapshot, so it is applied without a prompt. Declining prints `The policy was not changed.` and exits `0`.

**Refusals**, exit `2`:

- No flags at all:

```text
Nothing to set. Pass --daily, --weekly, --monthly or --frequency-hours.
Each retention flag also takes the literal `default`, which restores this organization's own value for that tier.
```

- A tier the plan does not allow changing:

```text
This organization's plan does not allow changing the monthly retention on `production`.
Run `surrealctl instance backup policy get` to see which tiers are editable.
```

- A value outside the plan's bounds, naming the bound it broke:

```text
Daily retention must be between 1 and 30 days on this plan; 90 was given.
```

- A `--frequency-hours` the plan does not offer, listing the intervals it does:

```text
A backup every 5 hours is not offered on this plan. Choose one of: 6, 12, 24.
```

## Related pages

- [Long-running operations](/docs/reference/cli/surrealctl/long-running-operations.md) — `--wait`, `--no-wait`, polling and exit code `10`
- [`org` commands](/docs/reference/cli/surrealctl/commands/org.md) — the organisation that owns these instances
- [`catalog` commands](/docs/reference/cli/surrealctl/commands/catalog.md) — the type, region and version slugs `create` and `update` expect
- [Installation](/docs/manage/surrealctl/install.md#the-surreal-handoff) — how `sql`, `import` and `export` find the `surreal` binary
- [Overview](/docs/reference/cli/surrealctl/overview.md) — the rest of the reference
- [SurrealDB CLI](/docs/reference/cli/surrealdb-cli/overview.md) — the data plane: `surreal sql`, `surreal import`, `surreal export`
