All rules Rule SR005 · DW
SurrealDB · beta
warning
DW · Deploy window
free in the CLI, --engine=surrealdb

What happens to existing records when a SurrealDB table becomes SCHEMAFULL?

Existing table switched to SCHEMAFULL

Warning: the statement succeeds, then writes fail, access changes, or the table is held up.

What happens

Observed on SurrealDB 3.0.2: a record carrying a field with no DEFINE FIELD stays readable after ALTER TABLE user SCHEMAFULL, but UPDATE of that record fails with "Found field 'legacy', but no such field exists for table 'user'", and so does a CREATE that sends the field.

Why it is dangerous on a populated table

SurrealDB checks a schema change against new writes, not the records already stored, so an empty table hides it: on a populated one every old record is a write waiting to fail, and whole-table work runs for the length of the table in one transaction.

Fires on

ALTER TABLE user SCHEMAFULL;

The safe pattern

Define every field the records and the running code use, strip the rest with UNSET in batches, and switch only when nothing undeclared is left.

-- 1. DEFINE FIELD for every field in use, e.g.
--      DEFINE FIELD nickname ON TABLE user TYPE option<string>;
-- 2. strip what is not declared, in batches:
--      UPDATE user UNSET legacy_flag WHERE legacy_flag IS NOT NONE;
-- 3. then, in a later migration: ALTER TABLE user SCHEMAFULL;

Fixtures

The rule ships with these files and the test suite runs them on every change: the first set must fire, the second must stay silent.

Fires (2)

alter schemafull
ALTER TABLE user SCHEMAFULL;
overwrite schemafull
DEFINE TABLE OVERWRITE user SCHEMAFULL PERMISSIONS FOR select WHERE id = $auth.id;

Stays silent (2)

alter schemaless
ALTER TABLE user SCHEMALESS;
new table
DEFINE TABLE user SCHEMAFULL;

How to check locally

Catch this before it ships

SurrealDB support is in beta: this rule runs locally in the free CLI over .surql migrations, static only, and not in the hosted service yet. No install, nothing leaves your machine:

npx bolvrk check migration.surql --engine=surrealdb