Docs

Transactions

Manual transaction control for grouping multiple statements atomically, and why try/catch alone does not roll one back.

Basic pattern

const begun = await CapacitorSqlite.beginTransaction({ database: 'myapp' });
if (!begun.success) throw new Error(begun.error.message);

try {
  const updated = await CapacitorSqlite.run({ database: 'myapp', statement: 'UPDATE ...', values: [] });
  if (!updated.success) throw new Error(updated.error.message);

  const batched = await CapacitorSqlite.runBatch({ database: 'myapp', set: [], transaction: false });
  if (!batched.success) throw new Error(batched.error.message);

  const committed = await CapacitorSqlite.commitTransaction({ database: 'myapp' });
  if (!committed.success) throw new Error(committed.error.message);
} catch (e) {
  const rolledBack = await CapacitorSqlite.rollbackTransaction({ database: 'myapp' });
  if (!rolledBack.success && rolledBack.error.code !== 'TRANSACTION_FAILED') {
    console.error('Rollback failed:', rolledBack.error);
  }
  throw e;
}

Why you must check success, not just catch

Every plugin method resolves to SqliteResult — SQL failures do not reject the Promise. A failed run(), runBatch(), or commitTransaction() resolves with success: false instead of throwing. The pattern above only reaches its catch block because each step explicitly throws when success is false; without that check, a failed statement inside the try block would be silently ignored and the transaction would still attempt to commit.

Nesting rules

Manual transactions are connection-scoped, one at a time:

  • Calling beginTransaction() again while one is already active returns TRANSACTION_FAILED.
  • Calling execute() or runBatch() with their default transaction: true while a manual transaction is active also returns TRANSACTION_FAILED — pass transaction: false on those calls so they participate in the existing transaction instead of nesting a new one, as shown for runBatch() above.

Cleanup

close() automatically rolls back any transaction still open on that connection — you do not need to roll back manually before closing.

OR ROLLBACK conflict clauses

A statement using SQLite's OR ROLLBACK conflict-resolution clause can end an active transaction on its own, outside the plugin's explicit commitTransaction()/rollbackTransaction() calls. Backends that mirror transaction state resynchronize that mirror after a statement using OR ROLLBACK fails, so subsequent calls see the correct (no-longer-in-transaction) state.

Next step

Bulk writes covers runBatch() and runMany() for grouping many writes efficiently, including how their own transaction option interacts with a manual transaction.

Last updated on July 17, 2026