SurrealDB
SurrealDB Docs Logo

Enter a search query

Navigation

Concepts

Transactions

Transactions

Transactions allow you to execute a group of queries atomically, meaning either all changes are applied or none are. This is essential for maintaining data consistency when performing related operations that must not be partially applied.

API References

MethodDescription
db.beginTransaction()Starts a new transaction
txn.commit()Commits the transaction, applying all changes
txn.cancel()Cancels the transaction, discarding all changes

Starting a transaction

Call .beginTransaction() on any Surreal or SurrealSession instance to start a new transaction. The returned SurrealTransaction object provides all the same query methods as a regular session, but every operation is executed within the transaction scope.

const txn = await db.beginTransaction();

Executing queries within a transaction

Use the transaction object to execute queries just as you would on the Surreal instance. All operations are held in a pending state until you commit or cancel.

const txn = await db.beginTransaction(); await txn.create(new RecordId('users', 'alice')) .content({ name: 'Alice', email: 'alice@example.com' }); await txn.create(new RecordId('users', 'bob')) .content({ name: 'Bob', email: 'bob@example.com' });

Committing changes

Call .commit() to apply all pending changes to the database. After committing, the transaction cannot be used again.

await txn.commit();

Cancelling and rolling back

Call .cancel() to discard all pending changes. This is typically done when an error occurs during the transaction. After cancelling, the transaction cannot be used again.

await txn.cancel();

Handling errors in transactions

Always wrap transaction logic in a try-catch block to ensure the transaction is cancelled if any operation fails. This prevents partial changes from being committed.

const txn = await db.beginTransaction(); try { const from = await txn.select(new RecordId('accounts', 'alice')); const to = await txn.select(new RecordId('accounts', 'bob')); if (from.balance < 100) { throw new Error('Insufficient funds'); } await txn.update(new RecordId('accounts', 'alice')) .merge({ balance: from.balance - 100 }); await txn.update(new RecordId('accounts', 'bob')) .merge({ balance: to.balance + 100 }); await txn.commit(); } catch (error) { await txn.cancel(); throw error; }

Best practices

Keep transactions short

Execute transactions quickly to avoid holding resources longer than necessary. Perform any validation or external API calls before starting the transaction.

if (!isValidEmail(email)) { throw new Error('Invalid email'); } const txn = await db.beginTransaction(); await txn.create(new RecordId('users', id)).content({ email }); await txn.commit();

Do not reuse transactions

Once a transaction is committed or cancelled, create a new one for subsequent operations.

const txn1 = await db.beginTransaction(); await txn1.create(record1).content(data1); await txn1.commit(); const txn2 = await db.beginTransaction(); await txn2.create(record2).content(data2); await txn2.commit();

Learn more