MongoDB Transactions and GraphQL Mutations
Some GraphQL mutations modify multiple MongoDB documents and require atomicity.
For example, placing an order might involve:
Create order
↓
Reduce inventory
↓
Create payment record
If the first two operations succeed but the third fails, the application may be left in an inconsistent state.
MongoDB supports transactions for appropriate deployment configurations. A service can use a session to group operations atomically.
Conceptually:
const session = await mongoose.startSession();
try {
await session.withTransaction(async () => {
await OrderModel.create([{ ...order }], { session });
await InventoryModel.updateOne(
{ productId },
{ $inc: { quantity: -quantity } },
{ session }
);
});
} finally {
await session.endSession();
}
The GraphQL resolver should not generally contain the transaction workflow. The application service should own the business transaction.
Also remember that a database transaction does not automatically make external side effects transactional. Sending an email or calling a payment provider cannot simply be rolled back because a MongoDB transaction aborts.
Distributed side effects require patterns such as outbox processing, idempotency, compensating actions, or carefully designed workflow orchestration.
A MongoDB transaction can protect MongoDB operations, but it cannot automatically roll back an email, payment provider call, message broker publication, or other external side effect.
- Transactions can protect related MongoDB operations.
- Transaction workflows belong in the application service layer.
- External side effects are not automatically part of database transactions.
- Distributed workflows may require outbox, idempotency, or compensation patterns.
Why is a MongoDB transaction not enough to make an order workflow fully atomic when a payment provider is involved?