RecordId<Tb, Id>

The RecordId class provides type-safe record identifiers in SurrealDB. Each record ID consists of a table name and an ID value, represented as table:id in SurrealQL.

Import:

import { RecordId } from 'surrealdb';

Source: value/record-id.ts

  • Tb extends string - The table name (string literal type for type safety)

  • Id - The ID value type (string, number, object, etc.)

Create a new record identifier.

Syntax

new RecordId(table, id, validate?)
ParameterTypeDescription
table TbThe table name.
id IdThe record ID value (string, number, object, array, or RecordId).
validate booleanWhether to validate the table name format (default: true).
// String IDs
const user = new RecordId('users', 'john');
const post = new RecordId('posts', '123');

// Numeric IDs
const product = new RecordId('products', 42);

// Complex/structured IDs
const metric = new RecordId('metrics', {
service: 'api',
timestamp: 1234567890
});

// Array IDs
const compound = new RecordId('items', ['type-a', 123]);

// Nested RecordId
const nested = new RecordId('links', new RecordId('users', 'alice'));

// Type-safe with generics
const typedUser = new RecordId<'users', string>('users', 'john');

The table name component.

Type: Tb

const userId = new RecordId('users', 'john');
console.log(userId.tb); // 'users'

The ID value component.

Type: Id

const userId = new RecordId('users', 'john');
console.log(userId.id); // 'john'

const productId = new RecordId('products', 42);
console.log(productId.id); // 42

Parse a record ID from its string representation.

Syntax

RecordId.parse(str)
ParameterTypeDescription
str stringThe record ID string (format: table:id).

RecordId - The parsed record ID

// Parse simple IDs
const user = RecordId.parse('users:john');
const post = RecordId.parse('posts:123');

// Parse complex IDs
const metric = RecordId.parse('metrics:{ service: "api", time: 1234567890 }');

// Use in queries
const userId = RecordId.parse('users:alice');
const user = await db.select(userId);

Create a record ID from various value types.

Syntax

RecordId.from(value)
ParameterTypeDescription
value unknownValue to convert to RecordId.

RecordId | undefined - The record ID or undefined if conversion fails

const rid = RecordId.from('users:john');
const same = RecordId.from(new RecordId('users', 'john'));

Convert the record ID to its string representation.

Syntax

recordId.toString()

string - String representation in format table:id

const userId = new RecordId('users', 'john');
console.log(userId.toString()); // 'users:john'

const productId = new RecordId('products', 42);
console.log(productId.toString()); // 'products:42'

const complex = new RecordId('items', { type: 'widget', id: 5 });
console.log(complex.toString()); // 'items:{ type: "widget", id: 5 }'

Serialize the record ID for JSON.

Syntax

recordId.toJSON()

string - JSON-safe string representation

const userId = new RecordId('users', 'john');
console.log(JSON.stringify(userId)); // '"users:john"'

Check if two record IDs are equal.

Syntax

recordId.equals(other)
ParameterTypeDescription
other unknownValue to compare.

boolean - True if equal

const a = new RecordId('users', 'john');
const b = new RecordId('users', 'john');
const c = new RecordId('users', 'jane');

console.log(a.equals(b)); // true
console.log(a.equals(c)); // false
import { Surreal, RecordId } from 'surrealdb';

const db = new Surreal();
await db.connect('ws://localhost:8000');

// Create record with specific ID
const user = await db.create(new RecordId('users', 'john'))
.content({
name: 'John Doe',
email: 'john@example.com'
});

// Select by record ID
const retrieved = await db.select(new RecordId('users', 'john'));

// Update by record ID
await db.update(new RecordId('users', 'john'))
.merge({ status: 'active' });

// Delete by record ID
await db.delete(new RecordId('users', 'john'));
interface User {
id: RecordId<'users', string>;
name: string;
email: string;
}

// TypeScript enforces correct table name
const userId: RecordId<'users', string> = new RecordId('users', 'alice');

// This would be a type error:
// const wrong: RecordId<'posts', string> = new RecordId('users', 'alice');

const user = await db.select<User>(userId);
// Time-series data with structured IDs
const metricId = new RecordId('metrics', {
service: 'api',
host: 'server-01',
timestamp: 1234567890
});

await db.create(metricId).content({
cpu: 45.2,
memory: 78.1
});

// Compound keys
const sessionId = new RecordId('sessions', {
userId: 'john',
deviceId: 'device-123'
});
// Parse user input
const userInput = 'users:john';
const userId = RecordId.parse(userInput);
const user = await db.select(userId);

// Parse from query results
const result = await db.query('SELECT id FROM users:john').collect();
const recordId = RecordId.parse(result[0].id);
// Create relationship using record IDs
const from = new RecordId('users', 'john');
const to = new RecordId('posts', '123');

const edge = await db.relate(
from,
new Table('likes'),
to,
{ timestamp: DateTime.now() }
);

console.log('Edge from:', edge.in); // RecordId('users', 'john')
console.log('Edge to:', edge.out); // RecordId('posts', '123')
import { Uuid } from 'surrealdb';

// Generate time-ordered IDs
const userId = new RecordId('users', Uuid.v7());

// Generate random IDs
const sessionId = new RecordId('sessions', Uuid.v4());

await db.create(userId).content({
name: 'Alice',
created: DateTime.now()
});
// Validate table names (enabled by default)
try {
const invalid = new RecordId('invalid-table!', 'id');
} catch (error) {
console.error('Invalid table name');
}

// Skip validation
const unvalidated = new RecordId('any-name', 'id', false);

The RecordIdRange class represents a range of record IDs for querying multiple records.

new RecordIdRange(table, begin, end)
ParameterTypeDescription
table stringThe table name.
begin string | number | RecordIdStart of the range (inclusive).
end string | number | RecordIdEnd of the range (exclusive).
import { RecordIdRange } from 'surrealdb';

// Select range of users from 'a' to 'f'
const range = new RecordIdRange('users', 'a', 'f');
const users = await db.select(range);

// Numeric range
const numRange = new RecordIdRange('items', 1, 100);
const items = await db.select(numRange);

// Update range
await db.update(new RecordIdRange('users', 'a', 'f'))
.merge({ verified: true });

// Delete range
await db.delete(new RecordIdRange('logs', '2024-01-01', '2024-02-01'));
// Good: Type-safe
type UserId = RecordId<'users', string>;
const userId: UserId = new RecordId('users', 'john');

// Better: Enforce at compile time
function getUser(id: RecordId<'users', string>) {
return db.select(id);
}
// Good: Type-safe with validation
const user = await db.select(new RecordId('users', 'john'));

// Avoid: String-based (no validation)
const user = await db.query('SELECT * FROM users:john').collect();
// Good: Structured composite key
const id = new RecordId('events', {
userId: 'john',
timestamp: Date.now()
});

// Avoid: String concatenation
const id = new RecordId('events', `john-${Date.now()}`);
// Good: Safe parsing
try {
const id = RecordId.parse(userInput);
const record = await db.select(id);
} catch (error) {
console.error('Invalid record ID format');
}

Was this page helpful?