Skip to content

@stratum-hq/mongodb

@stratum-hq/mongodb adds multi-tenant document isolation for applications using MongoDB or Mongoose. Three isolation strategies are available: shared collection, collection-per-tenant, and database-per-tenant.

npm install @stratum-hq/mongodb mongodb

Optional: mongoose for the auto-scoping plugin. The plugin supports Mongoose 8 and Mongoose 9 (peer range ^8.0.0 || ^9.0.0).

import { MongoClient } from "mongodb";
import { MongoSharedAdapter } from "@stratum-hq/mongodb";
const client = new MongoClient(process.env.MONGODB_URI!);
const adapter = new MongoSharedAdapter({
client,
databaseName: "myapp",
});
// Scoped collection auto-injects tenant_id into every query
const orders = adapter.scopedCollection("acme", "orders");
await orders.insertOne({ product: "Widget", quantity: 5 });
const results = await orders.find({}).toArray(); // only acme's orders

A filter may name the current tenant (tenant_id: "acme" or { $eq: "acme" }), but any other condition on tenant_id throws, whether at the top level or inside $and, $or or $nor: another tenant’s ID, a query operator such as $in or $ne, or a dotted tenant_id.* path. This applies to every filter of the scoped collection, including bulkWrite filters and a find cursor’s filter(). Use the raw collection for cross-tenant admin queries.

  • Three isolation strategies: shared collection, collection-per-tenant, database-per-tenant
  • Mongoose plugin: auto-injects tenant_id via AsyncLocalStorage on save, find, update, delete, and aggregate
  • Fail-closed proxy: blocks unsafe aggregate stages ($lookup, $merge, $out) that could bypass isolation
  • GDPR purge: purgeTenantData() with Promise.allSettled for partial-failure resilience
  • LRU pool manager: for database-per-tenant, manages connection pools with configurable eviction

See the MongoDB Multi-Tenancy guide for strategy selection, security tradeoffs, Mongoose plugin setup, ALS context wiring, and performance tuning.