surformSurrealDB schemas, declared

Types (kinds)

Every field's type is SurrealDB's own kind grammar, passed through verbatim — Surform adds no spellings and hides none. This page covers the shapes you'll use most; SurrealQL's kind grammar is the complete reference.

Scalars

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table kinds {
  schemafull;
  a_string: string;
  an_int: int;
  a_float: float;
  a_number: number;
  a_decimal: decimal;
  a_bool: bool;
  a_datetime: datetime;
  a_duration: duration;
  a_uuid: uuid;
  some_bytes: bytes;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE kinds TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE a_string ON kinds TYPE string;
DEFINE FIELD OVERWRITE an_int ON kinds TYPE int;
DEFINE FIELD OVERWRITE a_float ON kinds TYPE float;
DEFINE FIELD OVERWRITE a_number ON kinds TYPE number;
DEFINE FIELD OVERWRITE a_decimal ON kinds TYPE decimal;
DEFINE FIELD OVERWRITE a_bool ON kinds TYPE bool;
DEFINE FIELD OVERWRITE a_datetime ON kinds TYPE datetime;
DEFINE FIELD OVERWRITE a_duration ON kinds TYPE duration;
DEFINE FIELD OVERWRITE a_uuid ON kinds TYPE uuid;
DEFINE FIELD OVERWRITE some_bytes ON kinds TYPE bytes;

number accepts both ints and floats; decimal is the exact-base-10 type for money.

Option: "or nothing"

option<T> marks a field the record may leave out. It is equivalent to the union none | T — SurrealQL's parser desugars one into the other, Surform knows they are the same type, and the canonical spelling is always option<T>:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table person {
  schemafull;
  nickname: option<string>;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE person TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE nickname ON person TYPE option<string>;

Collections

array<T> lists, set<T> unique lists, both with optional fixed length; object for free-form nesting:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table order {
  schemafull;
  items: array<string>;
  matrix: array<float, 3>;
  lottery: set<int>;
  meta: object;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE `order` TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE items ON `order` TYPE array<string>;
DEFINE FIELD OVERWRITE matrix ON `order` TYPE array<float, 3>;
DEFINE FIELD OVERWRITE lottery ON `order` TYPE set<int>;
DEFINE FIELD OVERWRITE meta ON `order` TYPE object;

Records: references to other tables

record<table> is a pointer to a record in a named table — the type SurrealDB's graph model runs on. List tables to constrain, or leave the list empty for any:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table post {
  schemafull;
  author: record<user>;
  related: record<post | comment>;
  parent: option<record<post>>;
  anything: record;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE `post` TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE author ON `post` TYPE record<user>;
DEFINE FIELD OVERWRITE related ON `post` TYPE record<post | comment>;
DEFINE FIELD OVERWRITE parent ON `post` TYPE option<record<post>>;
DEFINE FIELD OVERWRITE anything ON `post` TYPE record;

Multiple tables inside record<…> join with | — it is a union. Which is the next stop:

Unions and literals

Types combine with |, and literal values are types — hand-rolled enums, one line:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table shirt {
  schemafull;
  size: 'small' | 'medium' | 'large';
  id_or_code: int | string;
  flags: array<'red' | 'green' | 'blue'>;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE shirt TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE size ON shirt TYPE 'small' | 'medium' | 'large';
DEFINE FIELD OVERWRITE id_or_code ON shirt TYPE int | string;
DEFINE FIELD OVERWRITE flags ON shirt TYPE array<'red' | 'green' | 'blue'>;

Inline object schemas

An object type can spell out its expected shape right in the header — the braces belong to the type grammar, not to a clause block:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table webhook {
  schemafull;
  payload: { a: string, b: number };
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE webhook TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE payload ON webhook TYPE { a: string, b: number };

Geometry and friends

Geography, tables-as-values, files, ranges, regexes — the remaining SurrealQL kinds all pass through:

applied to SurrealDB 3.3.0
schema.surdl
sdl
namespace acme;
database shop;

table place {
  schemafull;
  location: geometry<point>;
  area: geometry<polygon>;
  attachment: file<photo>;
  window: range;
  pattern: regex;
};
surform build
sql
DEFINE NAMESPACE OVERWRITE acme;
USE NS acme;
DEFINE DATABASE OVERWRITE shop;
USE NS acme DB shop;
DEFINE TABLE OVERWRITE place TYPE NORMAL SCHEMAFULL;
DEFINE FIELD OVERWRITE location ON place TYPE geometry<point>;
DEFINE FIELD OVERWRITE area ON place TYPE geometry<polygon>;
DEFINE FIELD OVERWRITE attachment ON place TYPE file<photo>;
DEFINE FIELD OVERWRITE window ON place TYPE range;
DEFINE FIELD OVERWRITE pattern ON place TYPE regex;

(range is its own whole kind here — it takes no inner type in the grammar.)

How types compare

Two spellings that parse to the same kind are the same type: option<string> ≡ none | string, int | int ≡ int, and unions compare flattened and deduplicated. This matters when you normalize: the database prints its desugared view (none | string), and the compiler folds it back to the option<T> you meant — your file doesn't churn when the database round-trips it.

Where next

  • Fields — everything a field block can do.
  • Relations — record<T> fields with lifelines (reference).
  • Indexes — indexes over these types.