Skip to main content

Transactions

nest-drizzle-native bridges transaction decorators to @nestjs-cls/transactional. It does not implement a separate transaction context. That keeps transaction state on the same CLS stack used by other Nest integrations.

Install the transaction peer:

npm i @nestjs-cls/transactional

Install the adapter for your Drizzle driver when needed. For example, the test suite uses:

npm i @nestjs-cls/transactional-adapter-drizzle-orm

Configure CLS

The exact adapter configuration depends on your driver. The important part is that the adapter points at the same Drizzle client token used by DrizzleModule.

import { ClsModule } from 'nestjs-cls';
import { ClsPluginTransactional } from '@nestjs-cls/transactional';
import { TransactionalAdapterDrizzleOrm } from '@nestjs-cls/transactional-adapter-drizzle-orm';
import { getDrizzleClientToken } from 'nest-drizzle-native';

@Module({
imports: [
DrizzleModule.forRoot({
schema,
connection: db,
}),
ClsModule.forRoot({
global: true,
plugins: [
new ClsPluginTransactional({
adapter: new TransactionalAdapterDrizzleOrm({
drizzleInstanceToken: getDrizzleClientToken(),
}),
enableTransactionProxy: true,
}),
],
}),
],
})
export class AppModule {}

For named connections, pass the same connection name to getDrizzleClientToken().

getDrizzleClientToken('analytics')

Use The Decorator

import { Injectable } from '@nestjs/common';
import { TransactionHost } from '@nestjs-cls/transactional';
import { Transactional } from 'nest-drizzle-native';

@Injectable()
export class UsersService {
constructor(private readonly txHost: TransactionHost<AppTxAdapter>) {}

@Transactional()
async createUser(name: string) {
await this.txHost.tx.insert(users).values({ name });
}
}

Rollback Behavior

Rollback behavior is owned by the configured CLS transaction adapter. In the package integration tests, a thrown error inside a @Transactional() method rolls back the real libSQL Drizzle transaction, and a successful method commits.

See the CLS transaction sample for the standard service-level pattern.

Direct Transaction Injection

Use @InjectTransaction() only when a low-level provider needs direct access to the current transaction object.

import { Injectable } from '@nestjs/common';
import { InjectTransaction } from 'nest-drizzle-native';

@Injectable()
export class InventoryRepository {
constructor(@InjectTransaction() private readonly tx: AppDatabase) {}

async reserve(sku: string, quantity: number) {
await this.tx.insert(reservations).values({ sku, quantity });
}
}

The service should still own the method-level @Transactional() boundary. See the manual transaction sample for a runnable commit and rollback example.

Testing Transactions

Use real Drizzle clients for transaction tests. Mocking a transaction decorator or mock client can prove that a service calls a method, but it cannot prove commit, rollback, isolation, or driver adapter behavior.