ORM Transaction Adapters
pg-boss operations such as send(), insert(), fetch(), and complete() accept a db option that lets you run them inside an existing database transaction. This is how you ensure that job creation (or completion) is atomic with your application's own writes — if the transaction rolls back, so does the job.
Each adapter wraps the ORM's transaction object as a pg-boss Db (the executeSql interface), so pg-boss can execute its own SQL within your transaction.
interface Db {
executeSql(text: string, values: any[]): Promise<{ rows: any[] }>;
}Knex
import { fromKnex } from 'pg-boss'
await knex.transaction(async (trx) => {
// your application writes ...
await trx('orders').insert({ item: 'widget', qty: 1 })
// schedule a pg-boss job in the same transaction
await boss.send('order-processing', { item: 'widget' }, { db: fromKnex(trx) })
})Kysely
import { fromKysely } from 'pg-boss'
await db.transaction().execute(async (trx) => {
await trx.insertInto('orders').values({ item: 'widget', qty: 1 }).execute()
await boss.send('order-processing', { item: 'widget' }, { db: fromKysely(trx) })
})Drizzle
The Drizzle adapter requires the sql tagged-template function from drizzle-orm as a second argument. This allows pg-boss to construct parameterised queries through Drizzle's public API without adding drizzle-orm as a runtime dependency.
import { fromDrizzle } from 'pg-boss'
import { sql } from 'drizzle-orm'
await db.transaction(async (tx) => {
await tx.insert(orders).values({ item: 'widget', qty: 1 })
await boss.send('order-processing', { item: 'widget' }, { db: fromDrizzle(tx, sql) })
})Prisma
Requires Prisma v7+ with @prisma/adapter-pg.
import { fromPrisma } from 'pg-boss'
await prisma.$transaction(async (tx) => {
await tx.order.create({ data: { item: 'widget', qty: 1 } })
await boss.send('order-processing', { item: 'widget' }, { db: fromPrisma(tx) })
})Rollback behaviour
When the ORM transaction is rolled back (either explicitly or by throwing an error), all pg-boss operations executed through the adapter are rolled back as well. This is the primary reason to use these adapters — to guarantee atomicity between your application writes and job scheduling.