Thanks everyone, I just found the problem is I can't chain the save() right after create() which will call the entity's save() fn instead of the entityManager's one, and start a new transaction.
async createPrice(dto, entityManager){
//wrong code
return entityManager.create(PriceEntity, {...}).save();
//works
const price = entityManager.create(PriceEntity, {...});
return entityManager.save(price);
}
}
Answer from C TC on Stack Overflow
» npm install @nestjs-cls/transactional
How to use a transaction across multiple services in nestjs - Stack Overflow
Adding Transactional Annotation to NestJS
nestjs / TypeOrm database transaction - Stack Overflow
Why I built typeorm-transactional-decorator
Thanks everyone, I just found the problem is I can't chain the save() right after create() which will call the entity's save() fn instead of the entityManager's one, and start a new transaction.
async createPrice(dto, entityManager){
//wrong code
return entityManager.create(PriceEntity, {...}).save();
//works
const price = entityManager.create(PriceEntity, {...});
return entityManager.save(price);
}
}
try to add @Transactional() decorator before insert function from your services typeorm transaction/ typeorm-transactional-cls-hooked
@Transactional()
public async createProduct(...) {
...
}
» npm install @hodfords/nestjs-transaction
» npm install @nestjs-cls/transactional-adapter-typeorm
Many solutions are available, they should all be based on SQL transaction management.
Personally I feel that the simplest way to achieve that is to use the same EntityManager instance when you execute code on your database. Then you can use something like:
getConnection().transaction(entityManager -> {
service1.doStuff1(entityManager);
service2.doStuff2(entityManager);
});
You can spawn a QueryRunner from an EntityManager instance that will be wrapped in the same transaction in case you execute raw SQL outside ORM operations. You need also to spawn Repository instances from EntityManager as well or they will execute code outside the main transaction.
typeorm-transactional uses CLS (Continuation Local Storage) to handle and propagate transactions between different repositories and service methods.
@Injectable()
export class PostService {
constructor(
private readonly authorRepository: AuthorRepository,
private readonly postRepository: PostRepository,
) {}
@Transactional() // will open a transaction if one doesn't already exist
async createPost(authorUsername: string, message: string): Promise<Post> {
const author = await this.authorRepository.create({ username: authorUsername });
return this.postRepository.save({ message, author_id: author.id });
}
}
I got tired of threading the EntityManager/QueryRunner through every layer of a modular NestJS backend—passing it as a parameter into every service and method. It was noisy, brittle, and honestly, a pain. I went hunting for a decorator-based solution for TypeORM transactions. I found a few, tried them, but they felt overconfigured and, crucially, the same transaction didn’t reliably propagate into deeply nested calls. Maybe I misused them—but the DX wasn’t there.
So I built typeorm-transactional-decorator: a small, focused layer that uses Node’s async hooks to carry a transactional context and patches TypeORM’s DataSource/EntityManager so repositories automatically bind to the current transaction if one exists. You get a dead-simple @Transactional decorator, @IgnoreTransaction to opt out where needed, reliable propagation into nested methods, automatic rollback on errors, and a TransactionResultManager to register side effects for onCommit/onRollback (think: delete an S3 file if the DB transaction fails). It’s based on typeorm-transactional, but simplified and tuned for a predictable, minimal workflow.
It slots neatly into NestJS via TypeOrmModule’s dataSourceFactory, or you can call addTransactionalDataSource(dataSource) in any Node app. The package grows as my needs evolve, but the north star is the same: minimal API, maximum ergonomics for real-world, layered architectures.
How are you handling TypeORM transactions?
NPM: https://www.npmjs.com/package/typeorm-transactional-decorator
Hello everyone,
I have been looking online for a nice way to handle database transactions in NestJs.
I looked at the examples in the docs and I read some articles online, but they all revolve around passing the EntityManager around.
I am guessing that I can't be the only one looking for a better alternative as passing that object around different methods across your codebase doesn't bother me only.
So, I am curious, did anyone find a better alternative to this? To somehow hide and abstract away the EntityManager?
Looking forward to hearing your thoughts!
Many thanks!