Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Drizzle ORM · Module

db.transaction

db.transaction runs related SQL operations atomically: all changes commit together, or the transaction rolls back. Use the supplied tx handle for queries, nested callbacks for savepoints, and tx.rollback() to abort from business logic.

How it works

Call db.transaction with an async callback to execute related statements through the transaction-scoped tx object. The callback may return a value; throwing an exception or calling tx.rollback() cancels the transaction, while nested transaction calls provide savepoints.

Syntax

await db.transaction(async (tx) => { /* statements using tx */ });

Parameters

NameTypeDescription
fn(tx) => Promise<T>Asynchronous callback receiving the transaction-scoped query handle.
configtransaction configurationOptional dialect-specific transaction configuration, such as isolation level, access mode, or deferrability.

Returns

The value returned by the transaction callback, resolved as a promise.

Key points

  • A transaction groups related SQL statements into one unit of work.
  • Successful work commits together rather than statement by statement.
  • Failure can undo the complete unit.
  • The API accepts an asynchronous callback and supplies a transaction-scoped handle.
  • Nested transaction callbacks are available for savepoint-based partial rollback.
  • Business rules can decide whether the transaction should be aborted.
  • The callback may produce a result for the caller.
  • Relational query APIs can execute through the transaction context.

Common mistakes

  • Calling tx.rollback() aborts the current transaction by throwing, so later statements in the callback do not run.

Example: Transfer funds atomically

import { drizzle } from "drizzle-orm/node-postgres";
import { eq, sql } from "drizzle-orm";
import { accounts, users } from "./schema";

const db = drizzle(process.env.DATABASE_URL!);

await db.transaction(async (tx) => {
  const [account] = await tx
    .select({ balance: accounts.balance })
    .from(accounts)
    .where(eq(users.name, "Dan"));

  if (account.balance < 100) {
    tx.rollback();
  }

  await tx.update(accounts)
    .set({ balance: sql`${accounts.balance} - 100` })
    .where(eq(users.name, "Dan"));
  await tx.update(accounts)
    .set({ balance: sql`${accounts.balance} + 100` })
    .where(eq(users.name, "Andrew"));
});

Runs both balance updates as one atomic unit and explicitly rolls back when the source account lacks funds.

When to use it

Atomic multi-step updates

Move funds between accounts while ensuring debit and credit succeed or fail together.

Business-rule rollback

Check application conditions and cancel before performing writes.

Nested work with savepoints

Group a smaller operation inside a larger unit with savepoint semantics.

Interview questions

QWhat does db.transaction provide?

A transaction groups SQL statements so they commit as one logical unit or roll back as one. Drizzle starts it with db.transaction(async (tx) => { ... }), and statements should use tx.

Follow-up: How can application logic abort it? Call tx.rollback() or let an exception escape; both prevent the transaction from committing.

QHow are nested transactions handled?

Use tx.transaction(async (tx2) => { ... }) inside an outer transaction. Drizzle maps nested transactions to savepoints, allowing the nested work to be independently rolled back.

Follow-up: What is the practical benefit? A failed nested operation can return to its savepoint while preserving the surrounding transaction, subject to the database dialect's behavior.

QCan a transaction return data?

The transaction callback can return a value, which becomes the resolved result of the transaction call. This lets a transaction perform writes and return selected data without a separate query.

Follow-up: Can relational queries run inside it? Yes; the transaction-scoped object can be used for relational queries as documented.

  • savepoints
  • nested transactions
  • relational queries
  • isolationLevel
  • accessMode
  • deferrable
  • tx.rollback

Source: Transactions - Drizzle ORM. Checked 2026-10-16.