Executing queries
The JavaScript SDK provides two ways to execute queries against SurrealDB: raw SurrealQL using the .query() method, and structured query builder methods like .select(), .create(), .update(), and .delete(). Both approaches support type-safe generics, chainable configuration, and multiple result formats.
API References
Running raw SurrealQL
The .query() method executes raw SurrealQL statements against the database. You can pass bindings as a second argument to safely inject variables into the query.
const [users] = await db.query<[User[]]>(
'SELECT * FROM users WHERE age > $min_age',
{ min_age: 18 }
);
When executing multiple statements, each result maps to a position in the generic type parameter.
const [users, posts] = await db.query<[User[], Post[]]>(`
SELECT * FROM users;
SELECT * FROM posts;
`);
You can also pass a bound query for automatic parameterization using the surql template tag.
import { surql } from 'surrealdb';
const minAge = 18;
const [users] = await db.query<[User[]]>(
surql`SELECT * FROM users WHERE age > ${minAge}`
);
Selecting records
The .select() method reads records from the database. You can pass a Table to select all records, a RecordId to select a specific record, or a RecordIdRange to select a range.
import { Table, RecordId } from 'surrealdb';
const allUsers = await db.select(new Table('users'));
const user = await db.select(new RecordId('users', 'john'));
Query builder methods return chainable promises, allowing you to configure the query before it executes.
import { gt } from 'surrealdb';
const users = await db.select(new Table('users'))
.fields('name', 'email', 'age')
.where(gt('age', 18))
.limit(10)
.start(0)
.fetch('posts');
In the above example, we use the gt() function to create a greater than condition. This function is part of the expression utilities that are available in the SDK. If you prefer to write raw condition, you can use the raw() function to insert the condition directly into the query.
import { raw } from 'surrealdb';
const users = await db.select(new Table('users'))
.fields('name', 'email', 'age')
.where(raw('age > 18'))
.limit(10)
.start(0)
.fetch('posts');
Creating records
The .create() method creates new records. Use .content() to set the record data. When passed a Table, SurrealDB generates a random ID. When passed a RecordId, the record is created with that specific ID.
const user = await db.create(new RecordId('users', 'john'))
.content({
name: 'John Doe',
email: 'john@example.com',
});
const autoId = await db.create(new Table('users'))
.content({ name: 'Jane Doe' });
Inserting records
The .insert() method inserts one or multiple records at once. This is more efficient than calling .create() in a loop when working with bulk data.
const users = await db.insert(new Table('users'), [
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' },
]);
Updating records
The .update() and .upsert() methods modify existing records. Instead of passing content as a second argument, you choose an update strategy by chaining .content(), .merge(), .replace(), or .patch().
Replace the entire record with new data. Any existing fields not included in the new data will be removed.
await db.update(new RecordId('users', 'john'))
.content({
name: 'John Smith',
email: 'john.smith@example.com',
});
Merge new fields into the existing record. Existing fields that are not specified remain unchanged.
await db.update(new RecordId('users', 'john'))
.merge({ email: 'new@example.com' });
Apply JSON Patch operations for fine-grained modifications.
await db.update(new RecordId('users', 'john'))
.patch([
{ op: 'replace', path: '/email', value: 'new@example.com' },
{ op: 'add', path: '/verified', value: true },
]);
You can also filter which records to update using .where().
await db.update(new Table('users'))
.merge({ verified: true })
.where('age >= 18');
Deleting records
The .delete() method removes records from the database. Like other query methods, it accepts a Table, RecordId, or RecordIdRange.
await db.delete(new RecordId('users', 'john'));
await db.delete(new Table('users'));
Creating graph relationships
The .relate() method creates edges between records in SurrealDB’s graph model. You specify the source record(s), the edge table, and the target record(s).
await db.relate(
new RecordId('users', 'john'),
new Table('likes'),
new RecordId('posts', '1'),
{ timestamp: new Date() },
);
Running functions
The .run() method executes SurrealDB functions or SurrealML models by name. You can pass arguments and optionally specify a model version.
const result = await db.run('fn::calculate_total', [100, 0.2]);
const prediction = await db.run('ml::predict', '1.0.0', [inputData]);
Setting session parameters
You can define parameters on the current session using .set() and remove them with .unset(). Session parameters are available in all subsequent queries as $name variables and persist for the lifetime of the session.
await db.set('current_user', {
first: 'Tobie',
last: 'Morgan Hitchcock',
});
await db.query('CREATE post SET author = $current_user');
await db.unset('current_user');
Collecting specific results
When running multi-statement queries, you can use .collect() to pick specific result indexes rather than receiving all results.
const [foo, bar] = await db.query(`
LET $a = 1;
LET $b = 2;
SELECT * FROM users;
SELECT * FROM posts;
`).collect<[User[], Post[]]>(2, 3);
Streaming query responses
The .stream() method returns an async iterable of response frames, allowing you to process results incrementally. Each frame is either a value, a completion signal with query stats, or an error.
const stream = db.query('SELECT * FROM large_table').stream();
for await (const frame of stream) {
if (frame.isValue<User>()) {
processUser(frame.value);
} else if (frame.isDone()) {
console.log('Duration:', frame.stats.duration);
} else if (frame.isError()) {
console.error(frame.error);
}
}
Streaming is currently not yet supported by SurrealDB, and this API exists primarily for future server-side record streaming.
Serializing results
The .json() method converts SurrealDB value types in query results to their JSON representations. This is useful when you need to serialize results for APIs or tools that don’t understand SurrealDB’s custom types.
const [products] = await db.query<[Product[]]>('SELECT * FROM product').json();
Learn more about the jsonify utility in the Utilities concept page.
The .responses() method returns the full response objects including success status, query stats, and error information for each statement.
const responses = await db.query('SELECT * FROM users; SELECT * FROM posts').responses();
for (const response of responses) {
if (response.success) {
console.log('Result:', response.result);
console.log('Duration:', response.stats?.duration);
} else {
console.error('Error:', response.error.message);
}
}
Learn more