npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nestjs-mongo-transactions

v1.1.0

Published

A simple and powerful NestJS package for handling MongoDB transactions with Mongoose using the @Transaction decorator and AsyncLocalStorage

Readme

NestJS MongoDB Transactions

CI NPM Version Coverage License

A simple and powerful NestJS package for handling MongoDB transactions with Mongoose using the @Transaction decorator. This package uses AsyncLocalStorage to automatically propagate transaction context to all nested MongoDB operations, making transaction management seamless and transparent.

Features

  • 🎯 Simple Decorator: Just add @Transaction() to any method
  • 🔄 Automatic Context Propagation: Uses AsyncLocalStorage to pass transaction context to nested calls
  • 🔌 Mongoose Plugin: Automatically attaches session to all MongoDB operations
  • 🏗️ NestJS Native: Designed specifically for NestJS applications
  • 🛡️ Type-Safe: Full TypeScript support
  • 📦 Zero Configuration: Works out of the box with minimal setup

Installation

npm install nestjs-mongo-transactions

Peer Dependencies

Make sure you have these installed:

npm install @nestjs/common @nestjs/mongoose mongoose reflect-metadata

Quick Start

1. Setup Mongoose Connection

In your main module (e.g., app.module.ts), register the transaction plugin:

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { createTransactionConnectionFactory } from 'nestjs-mongo-transactions';

@Module({
  imports: [
    MongooseModule.forRootAsync({
      useFactory: () => ({
        uri: 'mongodb://localhost:27017/mydb',
        // Register the transaction plugin
        connectionFactory: createTransactionConnectionFactory(),
      }),
    }),
  ],
})
export class AppModule {}

2. Use the @Transaction Decorator

Simply add @Transaction() to any method where you want to use transactions:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Transaction } from 'nestjs-mongo-transactions';

@Injectable()
export class UserService {
  constructor(
    @InjectModel('User') private userModel: Model<User>,
    @InjectModel('Account') private accountModel: Model<Account>,
  ) {}

  @Transaction()
  async createUserWithAccount(userData: any, accountData: any) {
    // Both operations will be in the same transaction
    const user = await this.userModel.create(userData);
    const account = await this.accountModel.create({
      ...accountData,
      userId: user._id,
    });

    // If this fails, both user and account creation will be rolled back
    if (!account) {
      throw new Error('Account creation failed');
    }

    return { user, account };
  }
}

3. Nested Calls Work Automatically

The transaction context propagates to nested service calls:

@Injectable()
export class OrderService {
  constructor(
    private userService: UserService,
    private paymentService: PaymentService,
    private inventoryService: InventoryService,
  ) {}

  @Transaction()
  async createOrder(orderData: any) {
    // All of these operations (and their nested calls) are in the same transaction
    const user = await this.userService.updateUser(orderData.userId, { ... });
    const payment = await this.paymentService.processPayment(orderData.payment);
    const inventory = await this.inventoryService.decreaseStock(orderData.items);

    // If any operation fails, everything rolls back
    return this.orderModel.create(orderData);
  }
}

@Injectable()
export class PaymentService {
  // No @Transaction decorator needed here - it inherits from the parent
  async processPayment(paymentData: any) {
    // This operation automatically uses the transaction from createOrder
    return this.paymentModel.create(paymentData);
  }
}

Advanced Usage

Multiple Connections

If you have multiple MongoDB connections, you can specify which connection to use:

@Transaction('secondary')
async myMethod() {
  // Uses the 'secondary' connection
}

Manual Transaction Control

For advanced use cases, you can access the transaction context directly:

import { getCurrentSession, runWithSession } from 'nestjs-mongo-transactions';

async function manualTransactionControl() {
  const session = getCurrentSession();
  if (session) {
    // You have access to the current session
    console.log('In transaction:', session.id);
  }
}

Alternative Plugin Registration

If you prefer more control, you can register the plugin manually:

import { registerTransactionPlugin } from 'nestjs-mongo-transactions';

@Module({
  imports: [
    MongooseModule.forRootAsync({
      useFactory: () => ({
        uri: 'mongodb://localhost:27017/mydb',
        connectionFactory: (connection) => {
          registerTransactionPlugin(connection);
          // Add your custom logic here
          return connection;
        },
      }),
    }),
  ],
})
export class AppModule {}

How It Works

  1. @Transaction Decorator: When you call a method decorated with @Transaction(), it:

    • Starts a MongoDB session
    • Begins a transaction
    • Stores the session in AsyncLocalStorage
    • Executes your method
    • Commits on success or rolls back on error
    • Cleans up the session
  2. Mongoose Plugin: The plugin automatically attaches the session from AsyncLocalStorage to all Mongoose operations:

    • Queries (find, findOne, update, delete, etc.)
    • Aggregations
    • Document saves
    • All nested operations
  3. AsyncLocalStorage: This Node.js feature maintains the transaction context across async calls without explicitly passing it through function parameters.

API Reference

Decorators

@Transaction(connectionName?: string)

Method decorator that wraps the method in a MongoDB transaction.

Parameters:

  • connectionName (optional): Name of the Mongoose connection to use

Functions

createTransactionConnectionFactory()

Creates a connection factory that registers the transaction plugin.

registerTransactionPlugin(connection: Connection)

Registers the transaction plugin on a Mongoose connection.

getCurrentSession(): ClientSession | undefined

Gets the current transaction session from AsyncLocalStorage.

runWithSession<T>(session: ClientSession, callback: () => T | Promise<T>): T | Promise<T>

Runs a callback with a given session in AsyncLocalStorage.

Important Notes

⚠️ MongoDB Transactions Requirement: MongoDB transactions only work with replica sets or sharded clusters. For local development, you can set up a single-node replica set:

# Start MongoDB with replica set
mongod --replSet rs0

# In MongoDB shell
rs.initiate()