> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# upgrade-check

surreal db upgrade-check on SurrealDB 3.3: a read-only check that lists the stored definitions and records that 4.0 refuses or changes, with severities, fixes and links, over a server's /upgrade-check route, through INFO, or on a stopped datastore.

The `upgrade-check` command checks a `3.3` datastore before it moves to `4.0`. It lists the stored definitions and records that `4.0` refuses, fails on or treats differently, each with a severity, the effect on `4.0`, a fix and a link to the [upgrade guide](/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x.md). The check only reads, and never runs a stored definition, so it is safe to run against a production server.

The command belongs to the `3.3` release line of the database and is not part of `4.0`, because the check has to run while the datastore can still go back to `3.3`. Upgrade to the latest `3.3` release to get it. If the default database component is already `4.0`, run the `3.3` one with `+3`, as in `surreal +3 db upgrade-check`. See [Version names](/docs/reference/cli/launcher.md#version-names).

<Synopsis>
surreal db upgrade-check [OPTIONS]
</Synopsis>

<OptionsTable
	title="Options"
	options={[
		{ "name": "--endpoint", "short": "-e", "value": "<ENDPOINT>", "default": "ws://localhost:8000", "description": "The server to check, or the path of a stopped datastore, such as `surrealkv://path/to/data` or `rocksdb://path/to/data`." },
		{ "name": "--username", "short": "-u", "value": "<USERNAME>", "env": "SURREAL_USER", "description": "Username to sign in with. Also accepted as `--user`." },
		{ "name": "--password", "short": "-p", "value": "<PASSWORD>", "env": "SURREAL_PASS", "description": "Password to sign in with. Also accepted as `--pass`." },
		{ "name": "--token", "short": "-t", "value": "<TOKEN>", "env": "SURREAL_TOKEN", "description": "Token to authenticate with, instead of a username and password." },
		{ "name": "--auth-level", "value": "<AUTH_LEVEL>", "default": "root", "env": "SURREAL_AUTH_LEVEL", "description": "Level the user is defined on: `root`, `namespace` or `database`. A namespace user needs `--namespace`, and a database user needs `--namespace` and `--database`." },
		{ "name": "--namespace", "value": "<NAMESPACE>", "env": "SURREAL_NAMESPACE", "description": "Check one namespace only. Also accepted as `--ns`." },
		{ "name": "--database", "value": "<DATABASE>", "env": "SURREAL_DATABASE", "description": "Check one database of the namespace only. Needs `--namespace`. Also accepted as `--db`." },
		{ "name": "--json", "description": "Print the report as JSON, in the shape the `/upgrade-check` HTTP route returns." },
		{ "name": "--scan-records", "value": "[ROWS]", "description": "Also read up to `ROWS` records of each table, to find problems in records as well as in definitions. Without a value, reads up to 1000. Off by default." },
		{ "name": "--scan-total", "value": "<ROWS>", "description": "With `--scan-records`, the most records read across all tables. The server's default is 100,000." },
		{ "name": "--scan-seconds", "value": "<SECONDS>", "description": "With `--scan-records`, the longest time the record scan runs. The server's default is 30." },
		{ "name": "--client-side", "description": "Read the definitions with `INFO` statements and run the check in the command, instead of asking the server to run it." },
		{ "name": "--log", "short": "-l", "value": "<LOG>", "default": "info", "env": "SURREAL_LOG", "description": "The logging level for the command-line tool. Possible values: `none`, `full`, `error`, `warn`, `info`, `debug`, `trace`." }
	]}
/>

## Example usage

To check every namespace of a running server, sign in as a root user:

```bash
surreal db upgrade-check --endpoint http://localhost:8000 --username root --password secret
```

Each finding gives its location, the reason, the rule that found it, what `4.0` does, the fix and a link. The last line gives the verdict and the counts. The report below comes from a database with a view whose `FROM` names its own table and an index on a datetime field:

```text title="Sample output"
[BLOCKING] shop/main table agg: view agg reads FROM its own table (view-reads-own-table)
    4.0:  Every write to a table the view reads fails with `Cannot maintain the view: it reads itself`.
    fix:  Define the view again with DEFINE TABLE OVERWRITE over the tables other than its own, or remove it.
    docs: https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#views-that-read-their-own-table
[warning] shop/main table ev ev_at: index keys at, which is typed datetime (index-on-datetime)
    4.0:  An index built by 3.x keeps the text order of datetimes, in which a whole second sorts after its fractions, so ORDER BY and ranges over the field can return records out of order or leave some out.
    fix:  Run REBUILD INDEX on this index once every node runs 4.0.
    docs: https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#datetimes-in-an-index
Not detectable from stored state:
  - 4.0 refuses CBOR tags 0, 9 and 13 (datetimes, UUIDs and durations as text), which some SDK releases send. Upgrade every SDK to a release that supports 4.0 before upgrading the server. (https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#cbor-text-forms-of-datetimes-uuids-and-durations)
  - The 3.x Rust SDK, the SDKs built on it and JavaScript SDK releases before 2.1 refuse a 4.0 server. The 4.0 SDKs connect to 3.x servers as well, so upgrade the SDKs first. (https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#sdk-version-checks)
  - Schema scripts, not stored definitions: 4.0 refuses a clause repeated in DEFINE TABLE, a DEFINE INDEX with two kinds, and a dec literal with more than 28 decimal places. The stored form of each is unaffected. (https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#a-clause-repeated-in-define-table)
  - Queries sent by applications are not stored, so the check cannot see them. Read the behaviour changes, such as results without ORDER BY and float to decimal comparisons. (https://surrealdb.com/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x#behaviour-changes)
Verdict: blocking. 1 namespace(s), 1 database(s), 5 definition(s): 1 blocking, 1 warning(s), 0 info, 0 unreadable scope(s). Checked by 3.3.6.
```

The notes at the end are in every report. They name changes that the stored state cannot show, such as the queries an application sends.

To check one database with a database user, and to read up to 500 records of each table as well:

```bash
surreal db upgrade-check -e http://localhost:8000 -u app -p hunter123 --auth-level database --ns shop --db main --scan-records 500
```

To check a datastore with no server running, give its path. The command opens the datastore itself and runs the check as the root owner, so stop the server first:

```bash
surreal db upgrade-check --endpoint surrealkv://path/to/data
```

## How the check runs

The command reaches the same rules in three ways:

| Endpoint | How the check runs |
| --- | --- |
| `http://`, `https://`, `ws://` or `wss://` | The command calls the server's [`/upgrade-check`](/docs/reference/rest-api/http-protocol.md#upgrade-check) route with your credentials, and the server reads its own catalog. |
| A server without the `/upgrade-check` route, or `--client-side` | A server from an earlier `3.3` release answers the route with `404`, and the command then reads each definition with `INFO` statements, and records with `SELECT`, and runs the check itself. The report's `checked_by` ends with `(client-side, through INFO)`. |
| A local path, such as `surrealkv://` or `rocksdb://` | The command opens the datastore in its own process. |

Over a gRPC endpoint, the command always uses `INFO` statements, because the route is served over HTTP only.

The check covers the scope of the user who signs in. A root user sees every namespace, and the report names the storage engine only for a root user. A namespace or database user sees only its own namespace or database, and naming another one with `--namespace` or `--database` is refused. A record user is refused.

## Severities and exit status

Every finding has one of three severities:

| Severity | Meaning |
| --- | --- |
| `blocking` | `4.0` refuses or fails on this definition or record, so change it before the upgrade. |
| `warning` | `4.0` keeps working, but gives different results or needs an action, such as `REBUILD INDEX`, a change to a schema script, or room on the disk. |
| `info` | No action is needed. |

The verdict is `blocking` when there is a blocking finding, `needs changes` (`needs_changes` in JSON) when there is a warning, and `compatible` otherwise. The command exits with a non-zero status when the verdict is `blocking`, or when it could not read a namespace, a database or a table, so a script can stop before the upgrade:

```text title="Error output"
1 blocking issue(s) found; resolve them before upgrading to 4.0
```

The rules, and what each finds, are listed under [Checking a datastore before the upgrade](/docs/build/migrating/from-old-surrealdb-versions/3x-to-4x.md#checking-a-datastore-before-the-upgrade).

## Record scan

Most rules read definitions only. Two rules read records, `record-table-value` and `record-not-object`, so they run only with `--scan-records`. The server limits the scan to 1,000,000 records of each table, 10,000,000 records in all and 600 seconds, whatever the options ask for. When a limit stops the scan, the summary line says `(scan cut short by its budget)`, and the JSON report has `"complete": false`.
