From harness-claude
Executes atomic database operations with Prisma $transaction, including sequential, interactive, nested writes, isolation levels, and timeouts.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:prisma-transactionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Execute atomic operations with Prisma $transaction, interactive transactions, and nested writes
Execute atomic operations with Prisma $transaction, interactive transactions, and nested writes
const [order, payment] = await prisma.$transaction([
prisma.order.create({ data: { userId, total: 99.99 } }),
prisma.payment.create({ data: { userId, amount: 99.99, status: 'PENDING' } }),
]);
const transfer = await prisma.$transaction(async (tx) => {
const sender = await tx.account.update({
where: { id: senderId },
data: { balance: { decrement: amount } },
});
if (sender.balance < 0) {
throw new Error('Insufficient funds');
}
const receiver = await tx.account.update({
where: { id: receiverId },
data: { balance: { increment: amount } },
});
return { sender, receiver };
});
Throwing inside the callback rolls back the entire transaction.
await prisma.$transaction(
async (tx) => {
/* ... */
},
{ isolationLevel: Prisma.TransactionIsolationLevel.Serializable }
);
await prisma.$transaction(
async (tx) => {
/* ... */
},
{ maxWait: 5000, timeout: 10000 }
);
maxWait — maximum time to wait for a connection from the pool (ms)timeout — maximum time the transaction can run before auto-rollback (ms)create/update with nested operations is already atomic:// This is already transactional — no $transaction wrapper needed
const user = await prisma.user.create({
data: {
email: '[email protected]',
profile: { create: { bio: 'Hello' } },
posts: { create: [{ title: 'Post 1' }, { title: 'Post 2' }] },
},
});
Use the tx client inside interactive transactions, not the global prisma client. Queries on the global client run outside the transaction.
Batch operations — combine createMany, updateMany, and deleteMany in a sequential transaction for bulk operations:
await prisma.$transaction([
prisma.notification.deleteMany({ where: { read: true, createdAt: { lt: cutoff } } }),
prisma.auditLog.create({ data: { action: 'CLEANUP', count: deletedCount } }),
]);
Prisma supports two transaction modes: sequential (array) and interactive (callback). Both produce a real database transaction with ACID guarantees.
Sequential vs interactive: Sequential transactions execute all operations in order but you cannot read intermediate results. Interactive transactions give you a transaction-scoped client (tx) that lets you read and branch on results. Use sequential for independent writes; use interactive when operations depend on each other.
Isolation levels: ReadUncommitted, ReadCommitted, RepeatableRead, Serializable. The default varies by provider (PostgreSQL defaults to ReadCommitted). Higher isolation levels prevent more anomalies but increase lock contention and deadlock risk.
Interactive transaction pitfalls:
tx client is only valid inside the callback — do not pass it to background jobsNested writes vs explicit transactions: Nested writes (connect, create, connectOrCreate within a single operation) are cleaner and more performant than wrapping individual operations in $transaction. Use explicit transactions only when you need conditional logic between operations.
Deadlocks: If two transactions lock the same rows in different order, the database detects the deadlock and aborts one transaction. Prisma surfaces this as error code P2034. Retry the transaction in application code:
async function withRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T> {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (e) {
if (e.code === 'P2034' && i < retries - 1) continue;
throw e;
}
}
throw new Error('Unreachable');
}
https://prisma.io/docs/orm/prisma-client/queries/transactions
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeExecutes atomic Drizzle operations with db.transaction(), nested transactions (savepoints), and rollback semantics for multi-step database operations.
Production patterns and non-obvious traps for Prisma ORM in TypeScript backends — schema design, query optimization, transactions, pagination, bulk operations, migrations, and serverless deployment gotchas.
Provides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.