Escape functions provide safe handling of identifiers and values in SurrealQL queries when you need to construct queries manually.
TipPrefer using
surqlorBoundQueryfor automatic parameterization. Use escape functions only when absolutely necessary.
Import:
import { escapeIdent, escapeKey, escapeRid, escapeValue } from 'surrealdb';
Source: utils/escape.ts
escapeIdent(name)Escape table names, field names, and other identifiers.
Signaturefunction escapeIdent(name: string): string
| Parameter | Type | Description |
|---|---|---|
name required | string | The identifier to escape. |
string - Escaped identifier
import { escapeIdent } from 'surrealdb'; // Simple identifiers (no escaping needed) console.log(escapeIdent('users')); // 'users' console.log(escapeIdent('first_name')); // 'first_name' // Special characters (wrapped in backticks) console.log(escapeIdent('user-table')); // '`user-table`' console.log(escapeIdent('my table')); // '`my table`' console.log(escapeIdent('user.name')); // '`user.name`' // Reserved keywords console.log(escapeIdent('select')); // '`select`' console.log(escapeIdent('from')); // '`from`'
escapeKey(key)Escape object keys for use in queries.
Signaturefunction escapeKey(key: string): string
string - Escaped key
const key = 'user-property'; console.log(escapeKey(key)); // Properly escaped for object notation
escapeRid(value)Escape record ID components.
Signaturefunction escapeRid(value: string | number): string
| Parameter | Type | Description |
|---|---|---|
value required | string | number | The record ID component to escape. |
string - Escaped record ID component
import { escapeRid } from 'surrealdb'; // Simple IDs console.log(escapeRid('john')); // 'john' console.log(escapeRid(123)); // '123' // IDs with special characters console.log(escapeRid('user-123')); // '`user-123`' console.log(escapeRid('user@email.com')); // '`user@email.com`'
escapeValue(value)Escape values for use in queries.
Signaturefunction escapeValue(value: unknown): string
| Parameter | Type | Description |
|---|---|---|
value required | unknown | The value to escape. |
string - Escaped value representation
import { escapeValue } from 'surrealdb'; // Strings console.log(escapeValue('hello')); // "'hello'" console.log(escapeValue("O'Reilly")); // "'O\\'Reilly'" // Numbers console.log(escapeValue(42)); // '42' console.log(escapeValue(3.14)); // '3.14' // Booleans console.log(escapeValue(true)); // 'true' console.log(escapeValue(false)); // 'false' // null/undefined console.log(escapeValue(null)); // 'null' console.log(escapeValue(undefined)); // 'none'
import { escapeIdent } from 'surrealdb'; async function selectFromTable(tableName: string) { // Validate and escape table name const safeTable = escapeIdent(tableName); // Use in query (still prefer Table class) const query = `SELECT * FROM ${safeTable}`; const [results] = await db.query(query).collect(); return results; } await selectFromTable('user-sessions'); // Safe
import { escapeIdent } from 'surrealdb'; async function selectFields(table: string, fields: string[]) { const escapedFields = fields.map(escapeIdent).join(', '); const escapedTable = escapeIdent(table); const query = `SELECT ${escapedFields} FROM ${escapedTable}`; const [results] = await db.query(query).collect(); return results; } await selectFields('users', ['first-name', 'last-name', 'email']);
// Only when you absolutely must build raw queries import { escapeIdent, escapeValue } from 'surrealdb'; function buildUnsafeQuery(table: string, filters: Record<string, unknown>) { const escapedTable = escapeIdent(table); const conditions = Object.entries(filters) .map(([key, value]) => { const field = escapeIdent(key); const val = escapeValue(value); return `${field} = ${val}`; }) .join(' AND '); return `SELECT * FROM ${escapedTable} WHERE ${conditions}`; } // Better: Use surql instead! const filters = { status: 'active', age: 18 }; const query = surql` SELECT * FROM users WHERE status = ${filters.status} AND age = ${filters.age} `;
surql or BoundQueryTable classRecordId classexpr// Good: Type-safe const table = new Table('users'); const users = await db.select(table); // Avoid: Manual escaping const escaped = escapeIdent('users'); const users = await db.query(`SELECT * FROM ${escaped}`).collect();
// Good: Validate first function safeQuery(tableName: string) { if (!isValidTable(tableName)) { throw new Error('Invalid table name'); } const escaped = escapeIdent(tableName); return `SELECT * FROM ${escaped}`; } // Avoid: Blind escaping function unsafeQuery(tableName: string) { return `SELECT * FROM ${escapeIdent(tableName)}`; }
// Good: Automatic parameterization const query = surql`SELECT * FROM users WHERE name = ${name}`; // Avoid: Manual escaping const query = `SELECT * FROM users WHERE name = ${escapeValue(name)}`;
WarningEscaping functions are NOT a complete defense against SQL injection. Always prefer parameterized queries using
surqlorBoundQuery.
// Secure: Parameterized const query = surql`SELECT * FROM users WHERE name = ${userInput}`; // Less secure: Manual escaping const query = `SELECT * FROM users WHERE name = ${escapeValue(userInput)}`; // Insecure: No escaping const query = `SELECT * FROM users WHERE name = '${userInput}'`;