I'm working with NestJS + Prisma and trying to find the best way to handle transactions across multiple services.
Problem:
Some services (like ResidentsService, FlatsService) need to work together inside the same Prisma $transaction, while others might run outside any transaction.
My solution so far:
I created a PrismaTransactionService (Scope.REQUEST) like this:
@Injectable({ scope: Scope.REQUEST }) export class PrismaTransactionService { private txClient?: Prisma.TransactionClient; constructor(private readonly prisma: PrismaService) {} setTransactionClient(client: Prisma.TransactionClient) { this.txClient = client; } get client() { return this.txClient ?? this.prisma; } }
In services, I always call prismaTransaction.client, like:
await this.prismaTransaction.client.resident.create(...);
If a transaction is active, it uses it. Otherwise, it falls back to normal PrismaService.
My concern:
Even simple read-only methods (findAll()) now go through PrismaTransactionService, even if no transaction is active.
Since PrismaTransactionService is request-scoped, it creates a new instance for every request.