Back to projects
Case study

nest-tenant

Multi-tenant library for NestJS — RLS and schema-per-tenant isolation, AsyncLocalStorage context, ORM adapters, CLI.

View Repository

At a glance

Purpose

Provide drop-in multi-tenancy for NestJS applications with multiple isolation strategies, automatic context propagation, and ORM integration.

Who it's for

NestJS developers building multi-tenant SaaS applications who want configurable tenant isolation without building it from scratch.

Core capabilities
  • Row-Level Security (RLS) tenant isolation
  • Schema-per-tenant isolation strategy
  • AsyncLocalStorage-based context propagation
Stack
TypeScriptNestJSPostgreSQLnpm

Context

Multi-tenancy is a solved problem, but implementing it correctly requires handling context propagation, database isolation, and ORM integration. Most NestJS projects implement this ad-hoc, leading to bugs and security gaps.

The Problem

Tenant context must flow through the entire request lifecycle without manual passing. Isolation strategies vary by use case—RLS for shared schemas, separate schemas for strict isolation. ORM integrations require middleware hooks.

Approach

nest-tenant uses AsyncLocalStorage to propagate tenant context automatically. Middleware extracts tenant identity from requests and sets context. ORM adapters apply isolation policies transparently. The library is published on npm for easy adoption.

Architecture

The library provides NestJS modules for tenant resolution, context storage, and database isolation. Middleware identifies the tenant from request headers, subdomains, or JWT claims. Context flows through AsyncLocalStorage without explicit passing.

ORM adapters intercept queries and apply tenant filtering. For RLS, they set session variables. For schema isolation, they switch schemas dynamically.

Tenant context propagation
// Middleware sets tenant context
@Injectable()
export class TenantMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const tenantId = extractTenant(req);
    TenantContext.run(tenantId, () => next());
  }
}

Isolation Strategies

RLS isolation uses PostgreSQL policies to filter rows by tenant. The adapter sets `app.tenant_id` session variable before queries. Schema isolation creates separate schemas per tenant—queries target the tenant's schema dynamically.

Both strategies are configurable per-module, allowing mixed isolation within an application.

ORM Integration

Adapters for Drizzle and Prisma apply isolation transparently. Developers query normally; the adapter injects tenant filtering. This prevents accidental cross-tenant data access at the ORM layer.

Tradeoffs

• **NestJS-only**: Tightly coupled to NestJS lifecycle and DI. • **PostgreSQL-focused**: RLS features assume PostgreSQL. Schema isolation works with other databases. • **Runtime overhead**: AsyncLocalStorage and middleware add small per-request overhead.