Skip to main content

Transactions

Use transaction functions to read and write from your database. A transaction function may contain multiple queries as well as TypeScript business logic and executes as a single database transaction.

Transaction functions must be annotated with the @Transaction decorator and must have a TransactionContext as their first argument. As with other DBOS functions, inputs and outputs must be serializable to JSON.

The TransactionContext provides a .client field you can use to interact with the database, so you don't need to worry about managing connections. DBOS supports Knex.js, Drizzle, TypeORM, and Prisma clients as well as raw SQL. You can configure which client to use in your dbos-config.yaml file. Knex is the default and we recommend using Knex.raw() for raw SQL.

Here are examples of a write and a read transaction function using each client.

interface GreetingRecord {
name: string;
note: string;
}

export class Greetings {
//...
@Transaction()
static async insertGreeting(ctxt: TransactionContext<Knex>, gr: GreetingRecord) {
await ctxt.client('greetings').insert(gr);
}

@Transaction({readOnly: true})
static async getGreetings(ctxt: TransactionContext<Knex>): Promise<GreetingRecord[]> {
return await ctxt.client<GreetingRecord>('greetings').select('*');
}
}

See our Knex guide for more information.

note

As shown above, we suggest decorating read transactions as @Transaction({readOnly: true}) for faster performance.

Schema Management

We strongly recommend you manage your database schema using migrations. Knex, TypeORM, and Prisma all provide rich support for schema management through migrations. Please see their guides for more detail:

If you are not using database transactions, you may wish to disable database migrations. In dbos-config.yaml, set your migrate: section as below:

migrate:
- echo 'No migrations'