SurrealDB has types that JavaScript does not: record IDs, nanosecond datetimes, arbitrary-precision decimals, and others. They live in @surrealdb/sqon, which also ships codecs and a few core utilities. The surrealdb package re-exports all of it, so either import path works:
// With the driver (usual choice)
import { RecordId, Table, DateTime } from 'surrealdb';
// SQON only (no database client)
import { RecordId, Table, DateTime } from '@surrealdb/sqon';The classes validate input, keep database precision, and plug into query methods and codecs.
API references
Class | Description |
|---|---|
RecordId | Type-safe record identifiers with table and ID components |
Table | Type-safe table references for query methods |
DateTime | Datetime values with nanosecond precision |
Duration | Time duration values with multiple unit support |
Decimal | Arbitrary precision decimal numbers |
Uuid | Universally unique identifiers (v4 and v7) |
Range | Bounded or unbounded range values |
FileRef | References to files stored in SurrealDB |
Geometry* | GeoJSON geometry types (Point, Line, Polygon, etc.) |
Type mapping
SurrealQL types map to JavaScript types as follows:
SurrealQL type | JavaScript type | Example |
|---|---|---|
bool | boolean | true, false |
int, float | number | 42, 3.14 |
Sized numbers, such as u8, i32and f32(SurrealDB 4.0) | number, or Decimalfor a u64above 9223372036854775807 | 200, 1.5 |
string | string | "hello" |
null | null | null |
none | undefined | undefined |
array | Array | [1, 2, 3] |
object | Object | {`{ key: "value" }`} |
set | Set | new Set([1, 2, 3]) |
bytes | Uint8Array | new Uint8Array([...]) |
record | RecordId | new RecordId('users', 'john') |
Table | new Table('users') | |
datetime | DateTime | DateTime.now() |
duration | Duration | Duration.parse('1h30m') |
decimal | Decimal | new Decimal('19.99') |
uuid | Uuid | Uuid.v7() |
geometry | Geometry* | new GeometryPoint([1, 2]) |
range | Range | new Range(1, 10) |
file | FileRef | record.avatar |
The figure below shows how some of these values travel as CBOR, which the SDK decodes into these classes, and how the same values look in the JSON that the HTTP /sql endpoint returns.


RecordId and Table
A RecordId is a table name plus an ID. A Table is a table reference on its own. From v2 onward, query methods expect a Table instance for table names, not a bare string, so table names are not confused with record IDs.
import { RecordId, Table } from 'surrealdb';
const userId = new RecordId('users', 'john');
const user = await db.select(userId);
const usersTable = new Table('users');
const allUsers = await db.select(usersTable);
const parsed = RecordId.parse('users:john');The ID component of a RecordId can be a string, number, bigint, Uuid, array, or object. The Table class also supports a type parameter for type-safe query results.
const users = new Table<User>('users');
const results: User[] = await db.select(users);DateTime and Duration
A DateTime is a timestamp with nanosecond precision. JavaScript's Date stops at milliseconds, so DateTime keeps what SurrealDB actually stored. A Duration follows SurrealQL duration syntax.
import { DateTime, Duration } from 'surrealdb';
const now = DateTime.now();
const parsed = DateTime.parse('2024-01-15T12:00:00.123456789Z');
const jsDate = now.toDate();
const iso = now.toString();
const duration = Duration.parse('1h30m45s');
const ms = duration.toMilliseconds();
const seconds = duration.toSeconds();Decimal
A Decimal holds a decimal without floating-point rounding. Construct it from a string when precision matters.
import { Decimal } from 'surrealdb';
const price = new Decimal('19.99');
const display = price.toString();
const number = price.toNumber(); Converting a Decimal to a number with .toNumber() may lose precision. Use .toString() when precision matters.
Uuid
A Uuid represents a universally unique identifier. The class supports generating both v4 (random) and v7 (time-ordered) UUIDs.
import { Uuid } from 'surrealdb';
const random = Uuid.v4();
const timeOrdered = Uuid.v7();
const parsed = Uuid.parse('550e8400-e29b-41d4-a716-446655440000');Range
A Range is a bounded or open-ended span of values. In SurrealQL you use ranges to slice record IDs or filter numbers and times. RecordIdRange is the variant for a table ID range.
import { Range, RecordIdRange } from 'surrealdb';
const numericRange = new Range(1, 10);
const idRange = new RecordIdRange('users', { begin: 'a', end: 'f' });
const slice = await db.select(idRange);FileRef
A FileRef points at a file stored in SurrealDB. You see one when working with file uploads; it carries bucket and key metadata.
const [record] = await db.query('SELECT avatar FROM user:john');
if (record.avatar instanceof FileRef) {
console.log(record.avatar.bucket);
console.log(record.avatar.key);
}Geometry types
The SDK provides classes for all GeoJSON geometry types: GeometryPoint, GeometryLine, GeometryPolygon, GeometryMultiPoint, GeometryMultiLine, GeometryMultiPolygon, and GeometryCollection.
import { GeometryPoint, GeometryLine, GeometryPolygon } from 'surrealdb';
const point = new GeometryPoint([longitude, latitude]);
const line = new GeometryLine([
new GeometryPoint([1, 2]),
new GeometryPoint([3, 4]),
]);Parsing from strings
Most classes accept the same string forms as SurrealQL. Invalid input throws.
const recordId = RecordId.parse('users:john');
const datetime = DateTime.parse('2024-01-15T12:00:00Z');
const duration = Duration.parse('1h30m45s');
const uuid = Uuid.parse('550e8400-e29b-41d4-a716-446655440000');Using native dates
By default, datetimes come back as DateTime. Set useNativeDates in codec options if you would rather work with Date and can accept millisecond precision.
const db = new Surreal({
codecOptions: {
useNativeDates: true,
},
});String prefixes
The surrealdb package includes tagged templates that mirror SurrealQL's s, d, r, and u prefixes. They are not part of @surrealdb/sqon.
import { s, d, r, u } from 'surrealdb';
const string = s`I am a string`;
const date = d`2024-05-06T17:44:57.085Z`;
const record = r`person:tobie`;
const uuid = u`92b84bde-39c8-4b4b-92f7-626096d6c4d9`;Best practices
Use type parameters for type-safe queries
const users = new Table<User>('users');
const results: User[] = await db.select(users);
const userId = new RecordId<'users', string>('users', 'john');Prefer value classes over raw strings
await db.select(new RecordId('users', 'john'));
// Avoid string-based queries when possible
await db.query('SELECT * FROM users:john');Validate parsed input
try {
const uuid = Uuid.parse(userInput);
} catch (error) {
console.error('Invalid UUID format');
}Learn more
Data types API reference for the full list of value class documentation
Codecs for serialising and deserialising value types
SurrealQL data model for the database-level type system
Utilities for comparing and converting values