{"id":28936289,"url":"https://github.com/lanemc/multi-tenant-saas-toolkit","last_synced_at":"2026-05-02T18:36:33.577Z","repository":{"id":300048308,"uuid":"1005028743","full_name":"lanemc/multi-tenant-saas-toolkit","owner":"lanemc","description":"🏢 Complete multi-tenancy solution for Node.js applications with TypeScript support","archived":false,"fork":false,"pushed_at":"2025-06-19T16:37:14.000Z","size":219,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T16:37:33.412Z","etag":null,"topics":["abac","authorization","express","multi-tenant","multitenancy","nestjs","nodejs","prisma","rbac","saas","tenant-isolation","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lanemc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-19T14:52:29.000Z","updated_at":"2025-06-19T16:37:18.000Z","dependencies_parsed_at":"2025-06-19T16:49:07.881Z","dependency_job_id":null,"html_url":"https://github.com/lanemc/multi-tenant-saas-toolkit","commit_stats":null,"previous_names":["lanemc/multi-tenant-saas-toolkit"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/lanemc/multi-tenant-saas-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lanemc%2Fmulti-tenant-saas-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lanemc%2Fmulti-tenant-saas-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lanemc%2Fmulti-tenant-saas-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lanemc%2Fmulti-tenant-saas-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lanemc","download_url":"https://codeload.github.com/lanemc/multi-tenant-saas-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lanemc%2Fmulti-tenant-saas-toolkit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261358697,"owners_count":23146674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abac","authorization","express","multi-tenant","multitenancy","nestjs","nodejs","prisma","rbac","saas","tenant-isolation","typescript"],"created_at":"2025-06-22T20:08:18.187Z","updated_at":"2026-05-02T18:36:33.566Z","avatar_url":"https://github.com/lanemc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏢 Multi-Tenant SaaS Toolkit\n\n[![npm version](https://badge.fury.io/js/@saaskit%2Fmultitenancy-core.svg)](https://badge.fury.io/js/@saaskit%2Fmultitenancy-core)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)\n\n\u003e **The fastest way to add multi-tenancy to your Node.js application** ⚡\n\nStop spending weeks implementing multi-tenancy from scratch. Get **production-ready tenant isolation**, **automatic data filtering**, and **enterprise-grade authorization** in minutes, not months.\n\n```bash\n# Get started in 30 seconds\nnpm install @saaskit/multitenancy-core\n```\n\n---\n\n## 🎯 Why This Toolkit?\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n**❌ Before: The Pain**\n- Weeks implementing tenant context\n- Manual query filtering everywhere\n- Security vulnerabilities\n- Inconsistent authorization\n- Framework lock-in\n- Data leakage risks\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n**✅ After: Pure Joy**\n- Setup in 5 minutes\n- Automatic tenant filtering\n- Security by default\n- Consistent RBAC/ABAC\n- Framework agnostic\n- Zero data leakage\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n## 🚀 30-Second Quick Start\n\n**1. Install the toolkit:**\n```bash\nnpm install @saaskit/multitenancy-core @saaskit/multitenancy-adapters\n```\n\n**2. Add one middleware:**\n```typescript\nimport { createTenantMiddleware } from '@saaskit/multitenancy-core';\n\napp.use(createTenantMiddleware({\n  resolution: { type: 'subdomain' },\n  dataStore: yourDataStore // We'll show you how!\n}));\n```\n\n**3. That's it!** 🎉 Your app now has:\n- ✅ Automatic tenant detection\n- ✅ Secure context isolation  \n- ✅ Ready for multi-tenancy\n\n---\n\n## 🎁 What You Get\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🏠 Smart Tenant Context\u003c/strong\u003e - Automatic tenant detection \u0026 isolation\u003c/summary\u003e\n\n- **AsyncLocalStorage magic** - Context follows your requests everywhere\n- **Multiple resolution strategies** - Subdomain, header, JWT, or custom\n- **Zero performance overhead** - Built for production scale\n- **Type-safe everywhere** - Full TypeScript support\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🔒 Bulletproof Data Isolation\u003c/strong\u003e - Never leak tenant data again\u003c/summary\u003e\n\n- **ORM integrations** - Prisma, Sequelize, Mongoose\n- **Automatic query filtering** - Set it once, works everywhere\n- **Multi-database support** - Separate databases per tenant\n- **Admin override** - Safe cross-tenant operations\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e👥 Enterprise Authorization\u003c/strong\u003e - RBAC + ABAC in one package\u003c/summary\u003e\n\n- **Pre-built roles** - Admin, member, viewer out of the box\n- **Flexible permissions** - Fine-grained access control\n- **Policy engine** - Complex authorization rules made simple\n- **Audit logging** - Track every action automatically\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🎯 Framework Freedom\u003c/strong\u003e - Works with your favorite stack\u003c/summary\u003e\n\n- **Express** - Drop-in middleware\n- **NestJS** - Decorators and guards\n- **Fastify** - High-performance plugins\n- **Any Node.js app** - Framework-agnostic core\n\n\u003c/details\u003e\n\n---\n\n## 🛠 Real-World Examples\n\n### 📦 Express + Prisma (Most Popular)\n\n```typescript\n// 1. Setup your data store (implement once, use everywhere)\nconst tenantDataStore = {\n  async getTenantById(id: string) {\n    return await prisma.tenant.findUnique({ where: { id } });\n  },\n  async getTenantBySubdomain(subdomain: string) {\n    return await prisma.tenant.findUnique({ where: { subdomain } });\n  },\n  async getUserTenant(userId: string, tenantId: string) {\n    return await prisma.tenantUser.findUnique({\n      where: { userId_tenantId: { userId, tenantId } },\n      include: { roles: true }\n    });\n  }\n};\n\n// 2. Add tenant middleware (handles everything automatically)\napp.use(createTenantMiddleware({\n  resolution: { type: 'subdomain' },\n  dataStore: tenantDataStore,\n  allowNoTenant: false // Strict tenant isolation\n}));\n\n// 3. Apply Prisma adapter (queries auto-filtered by tenant)\nimport { applyPrismaAdapter } from '@saaskit/multitenancy-adapters';\n\napplyPrismaAdapter(prisma, {\n  tenantField: 'tenantId',\n  models: ['User', 'Project', 'Task', 'Invoice']\n});\n\n// 4. Use anywhere - tenant context is automatic!\napp.get('/api/projects', async (req, res) =\u003e {\n  // Only returns projects for current tenant - automatically!\n  const projects = await prisma.project.findMany();\n  res.json(projects);\n});\n\n// 5. Add role-based protection\napp.delete('/api/projects/:id', \n  requireRole('admin', 'project-manager'),\n  async (req, res) =\u003e {\n    await prisma.project.delete({ where: { id: req.params.id } });\n    res.json({ success: true });\n  }\n);\n```\n\n### 🏗 NestJS + TypeORM (Enterprise)\n\n```typescript\n// app.module.ts\nimport { MultitenancyModule } from '@saaskit/multitenancy-nestjs';\n\n@Module({\n  imports: [\n    MultitenancyModule.forRoot({\n      resolution: { type: 'header', headerName: 'x-tenant-id' },\n      dataStore: TypeOrmTenantDataStore\n    })\n  ]\n})\nexport class AppModule {}\n\n// projects.controller.ts\n@Controller('projects')\n@UseGuards(TenantAuthGuard)\nexport class ProjectsController {\n  \n  @Get()\n  @Roles('member', 'admin')\n  async findAll(@TenantContext() context: TenantContext) {\n    // Automatically filtered by tenant\n    return this.projectsService.findAll();\n  }\n\n  @Delete(':id')\n  @Permissions('projects:delete')\n  async remove(@Param('id') id: string) {\n    return this.projectsService.remove(id);\n  }\n}\n```\n\n### ⚡ Fastify + Mongoose (High Performance)\n\n```typescript\n// Register the plugin\nawait fastify.register(require('@saaskit/multitenancy-fastify'), {\n  resolution: { type: 'subdomain' },\n  dataStore: mongoTenantDataStore\n});\n\n// Apply Mongoose plugin globally\nimport { mongooseTenantPlugin } from '@saaskit/multitenancy-adapters';\n\nmongoose.plugin(mongooseTenantPlugin, { \n  tenantField: 'tenantId',\n  indexTenant: true // Automatic indexing\n});\n\n// Use in routes\nfastify.get('/api/users', {\n  preHandler: [fastify.requireTenant, fastify.requireRole('admin')]\n}, async (request, reply) =\u003e {\n  // Auto-filtered by tenant\n  const users = await User.find();\n  return users;\n});\n```\n\n---\n\n## 🎨 Tenant Resolution Strategies\n\nChoose the strategy that fits your architecture:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eStrategy\u003c/th\u003e\n\u003cth\u003eUse Case\u003c/th\u003e\n\u003cth\u003eExample\u003c/th\u003e\n\u003cth\u003eSetup\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e🌐 Subdomain\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eCustomer-facing SaaS\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eacme.yoursaas.com\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\n{\n  resolution: { \n    type: 'subdomain' \n  }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e📋 Header\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eAPI-first, mobile apps\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eX-Tenant-ID: acme\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\n{\n  resolution: { \n    type: 'header',\n    headerName: 'x-tenant-id'\n  }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e🎫 JWT Token\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eMicroservices, SPAs\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e{ tenantId: \"acme\" }\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\n{\n  resolution: { \n    type: 'token',\n    tokenClaim: 'tenantId'\n  }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e⚙️ Custom\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eComplex routing logic\u003c/td\u003e\n\u003ctd\u003eAPI key, path, etc.\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\n{\n  resolution: { \n    type: 'custom',\n    customResolver: async (req) =\u003e {\n      const apiKey = req.headers['x-api-key'];\n      const client = await getClientByApiKey(apiKey);\n      return client?.tenantId;\n    }\n  }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n## 🔐 Authorization Made Simple\n\n### Quick Role Setup\n\n```typescript\nimport { RoleManager } from '@saaskit/multitenancy-auth';\n\nconst roleManager = new RoleManager({\n  roles: [\n    {\n      name: 'admin',\n      permissions: [\n        'users:*',        // All user operations\n        'projects:*',     // All project operations  \n        'billing:*',      // Billing management\n        'settings:*'      // Tenant settings\n      ]\n    },\n    {\n      name: 'project-manager', \n      permissions: [\n        'users:read',\n        'projects:*',     // Full project access\n        'tasks:*'\n      ]\n    },\n    {\n      name: 'member',\n      permissions: [\n        'users:read',\n        'projects:read',\n        'projects:write', // Can edit projects\n        'tasks:*'\n      ]\n    },\n    {\n      name: 'viewer',\n      permissions: [\n        'users:read',\n        'projects:read',\n        'tasks:read'\n      ]\n    }\n  ]\n});\n```\n\n### Smart Permission Hierarchies\n\n```typescript\n// Set up permission inheritance\nroleManager.setPermissionHierarchy({\n  'users:manage': ['users:read', 'users:write', 'users:delete'],\n  'projects:manage': ['projects:read', 'projects:write', 'projects:delete'],\n  'admin:*': ['users:manage', 'projects:manage', 'billing:manage']\n});\n\n// Now 'admin:*' automatically includes all sub-permissions!\n```\n\n### Advanced ABAC Policies\n\n```typescript\nimport { PolicyEngine } from '@saaskit/multitenancy-auth';\n\nconst policyEngine = new PolicyEngine();\n\n// Resource ownership policy\npolicyEngine.registerPolicy({\n  id: 'resource-ownership',\n  name: 'Users can manage their own resources',\n  effect: 'allow',\n  actions: ['read', 'write', 'delete'],\n  resources: ['project', 'task', 'document'],\n  conditions: [{\n    attribute: 'resource.attributes.ownerId',\n    operator: 'eq',\n    value: '${subject.id}' // Dynamic value\n  }]\n});\n\n// Time-based access policy  \npolicyEngine.registerPolicy(\n  PolicyEngine.createTimeBasedPolicy(\n    'business-hours',\n    'Allow admin access only during business hours',\n    ['admin:*'],\n    ['*'],\n    { start: '09:00', end: '17:00', timezone: 'UTC' }\n  )\n);\n\n// IP-based restrictions\npolicyEngine.registerPolicy({\n  id: 'ip-whitelist',\n  name: 'Restrict admin access to office IPs',\n  effect: 'allow', \n  actions: ['admin:*'],\n  resources: ['*'],\n  conditions: [{\n    attribute: 'environment.ipAddress',\n    operator: 'in',\n    value: ['192.168.1.0/24', '10.0.0.0/8']\n  }]\n});\n```\n\n---\n\n## 🗃 Database Integration\n\n### Prisma (Recommended)\n\n```typescript\n// schema.prisma\nmodel User {\n  id       String @id @default(cuid())\n  email    String\n  tenantId String // Required field\n  \n  @@unique([email, tenantId])\n  @@index([tenantId])\n}\n\nmodel Project {\n  id          String @id @default(cuid()) \n  name        String\n  tenantId    String // Required field\n  ownerId     String\n  \n  owner       User   @relation(fields: [ownerId], references: [id])\n  \n  @@index([tenantId])\n  @@index([tenantId, ownerId])\n}\n```\n\n```typescript\n// Apply the adapter\nimport { applyPrismaAdapter } from '@saaskit/multitenancy-adapters';\n\napplyPrismaAdapter(prisma, {\n  tenantField: 'tenantId',\n  models: ['User', 'Project', 'Task'], // Auto-filtered models\n  exclude: ['SystemLog'], // Skip certain models\n  onViolation: 'throw' // or 'warn' for development\n});\n\n// All queries now automatically filtered by tenant!\nconst users = await prisma.user.findMany(); // Only current tenant's users\nconst projects = await prisma.project.findMany(); // Only current tenant's projects\n```\n\n### Sequelize\n\n```typescript\n// models/User.js\nimport { DataTypes } from 'sequelize';\nimport { applySequelizeAdapter } from '@saaskit/multitenancy-adapters';\n\nconst User = sequelize.define('User', {\n  email: DataTypes.STRING,\n  tenantId: {\n    type: DataTypes.STRING,\n    allowNull: false\n  }\n});\n\n// Apply tenant filtering\napplySequelizeAdapter(User, {\n  tenantField: 'tenantId',\n  autoScope: true\n});\n\n// Usage - automatically scoped to tenant\nconst users = await User.findAll(); // Only current tenant's users\n```\n\n### Mongoose\n\n```typescript\n// models/User.js\nimport mongoose from 'mongoose';\nimport { mongooseTenantPlugin } from '@saaskit/multitenancy-adapters';\n\nconst userSchema = new mongoose.Schema({\n  email: String,\n  name: String\n  // tenantId added automatically by plugin\n});\n\n// Apply the plugin\nuserSchema.plugin(mongooseTenantPlugin, {\n  tenantField: 'tenantId',\n  indexTenant: true,\n  autoPopulate: true\n});\n\nconst User = mongoose.model('User', userSchema);\n\n// Usage - automatically scoped\nconst users = await User.find(); // Only current tenant's users\n```\n\n---\n\n## 🏗 Advanced Patterns\n\n### Multi-Database Architecture\n\nPerfect for enterprise customers who need dedicated databases:\n\n```typescript\nimport { TenantConnectionManager } from '@saaskit/multitenancy-adapters';\n\nconst connectionManager = new TenantConnectionManager({\n  default: process.env.DEFAULT_DATABASE_URL,\n  resolver: async (tenantId: string) =\u003e {\n    const tenant = await getTenant(tenantId);\n    return tenant.dedicatedDb ? tenant.databaseUrl : 'default';\n  },\n  pooling: {\n    max: 10,\n    idleTimeout: 30000\n  }\n});\n\n// Use in your middleware\napp.use(async (req, res, next) =\u003e {\n  const tenantId = getCurrentTenantId();\n  const connection = await connectionManager.getConnection(tenantId);\n  req.db = connection;\n  next();\n});\n```\n\n### Tenant Lifecycle Management\n\n```typescript\nimport { TenantManager } from '@saaskit/multitenancy-core';\n\nconst tenantManager = new TenantManager({\n  onCreate: async (tenant) =\u003e {\n    // Setup default data, send welcome email, etc.\n    await setupDefaultData(tenant.id);\n    await sendWelcomeEmail(tenant.ownerEmail);\n  },\n  onSuspend: async (tenant) =\u003e {\n    // Cleanup resources, notify users\n    await cleanupResources(tenant.id);\n  },\n  onDelete: async (tenant) =\u003e {\n    // Full cleanup, data export, etc.\n    await exportTenantData(tenant.id);\n    await deleteTenantData(tenant.id);\n  }\n});\n\n// Create a new tenant\nconst newTenant = await tenantManager.create({\n  name: 'Acme Corp',\n  subdomain: 'acme',\n  plan: 'professional',\n  ownerEmail: 'admin@acme.com'\n});\n```\n\n### Audit Logging\n\nTrack everything automatically:\n\n```typescript\nimport { AuditLogger } from '@saaskit/multitenancy-core';\n\nconst auditLogger = AuditLogger.getInstance({\n  store: new DatabaseAuditStore(prisma),\n  sensitiveFields: ['password', 'apiKey', 'secret']\n});\n\n// Automatic logging with decorator\n@AuditLog('user:update')\nasync function updateUser(id: string, data: any) {\n  return await prisma.user.update({\n    where: { id },\n    data\n  });\n}\n\n// Manual logging\nawait auditLogger.log({\n  action: 'project:create',\n  resource: { type: 'project', id: project.id },\n  result: 'success',\n  metadata: { name: project.name }\n});\n\n// Query audit logs\nconst recentActivity = await auditLogger.query({\n  actions: ['user:login', 'user:logout'],\n  dateRange: { start: yesterday, end: now },\n  limit: 100\n});\n```\n\n---\n\n## 🐛 Troubleshooting \u0026 FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🔍 Tenant not detected / Context is undefined\u003c/strong\u003e\u003c/summary\u003e\n\n**Common causes:**\n1. Middleware not registered or registered after routes\n2. Async context lost in callbacks\n3. Missing tenant data in resolution strategy\n\n**Solutions:**\n```typescript\n// ✅ Correct: Register middleware BEFORE routes\napp.use(createTenantMiddleware(config));\napp.use('/api', apiRoutes);\n\n// ❌ Wrong: Middleware after routes\napp.use('/api', apiRoutes);\napp.use(createTenantMiddleware(config));\n\n// ✅ Preserve async context in callbacks\nimport { tenantContext } from '@saaskit/multitenancy-core';\n\nsetTimeout(() =\u003e {\n  // Use runAsync to preserve context\n  tenantContext.runAsync(currentContext, async () =\u003e {\n    const tenant = tenantContext.getCurrentTenant();\n    // ... your code\n  });\n}, 1000);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e⚡ Performance Issues\u003c/strong\u003e\u003c/summary\u003e\n\n**Optimization tips:**\n\n1. **Enable connection pooling:**\n```typescript\napplyPrismaAdapter(prisma, {\n  tenantField: 'tenantId',\n  models: ['User', 'Project'],\n  caching: {\n    enabled: true,\n    ttl: 300 // 5 minutes\n  }\n});\n```\n\n2. **Add database indexes:**\n```sql\n-- Always index tenant fields\nCREATE INDEX idx_users_tenant_id ON users(tenant_id);\nCREATE INDEX idx_projects_tenant_id ON projects(tenant_id);\n\n-- Composite indexes for common queries\nCREATE INDEX idx_projects_tenant_owner ON projects(tenant_id, owner_id);\n```\n\n3. **Use tenant-aware caching:**\n```typescript\nimport { TenantCache } from '@saaskit/multitenancy-core';\n\nconst cache = new TenantCache(redisClient);\n\n// Automatically scoped to current tenant\nawait cache.set('user-preferences', preferences);\nconst cached = await cache.get('user-preferences');\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🔒 Data Leakage Prevention\u003c/strong\u003e\u003c/summary\u003e\n\n**Best practices:**\n\n1. **Always validate tenant access:**\n```typescript\napp.get('/api/projects/:id', async (req, res) =\u003e {\n  const project = await prisma.project.findUnique({\n    where: { id: req.params.id }\n  });\n  \n  // ✅ Double-check tenant ownership\n  const currentTenant = tenantContext.getCurrentTenantId();\n  if (project.tenantId !== currentTenant) {\n    return res.status(404).json({ error: 'Project not found' });\n  }\n  \n  res.json(project);\n});\n```\n\n2. **Use strict mode:**\n```typescript\napp.use(createTenantMiddleware({\n  resolution: { type: 'subdomain' },\n  dataStore: tenantDataStore,\n  allowNoTenant: false, // ✅ Strict: Reject requests without tenant\n  validateAccess: true   // ✅ Validate user belongs to tenant\n}));\n```\n\n3. **Enable audit logging:**\n```typescript\n// Track all data access\n@AuditLog('data:access')\nasync function getData() {\n  // Your data access code\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🧪 Testing Multi-Tenant Code\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport { TenantContextManager } from '@saaskit/multitenancy-core';\n\ndescribe('Multi-tenant API', () =\u003e {\n  const tenantContext = TenantContextManager.getInstance();\n  \n  it('should isolate data by tenant', async () =\u003e {\n    // Setup test tenants\n    const tenant1 = { id: 'tenant1', name: 'Acme Corp' };\n    const tenant2 = { id: 'tenant2', name: 'Globex Corp' };\n    \n    // Test with tenant1 context\n    await tenantContext.runAsync({ tenant: tenant1 }, async () =\u003e {\n      const projects = await getProjects();\n      expect(projects).toHaveLength(3); // tenant1 has 3 projects\n    });\n    \n    // Test with tenant2 context  \n    await tenantContext.runAsync({ tenant: tenant2 }, async () =\u003e {\n      const projects = await getProjects();\n      expect(projects).toHaveLength(1); // tenant2 has 1 project\n    });\n  });\n  \n  it('should enforce role-based access', async () =\u003e {\n    const memberContext = {\n      tenant: { id: 'tenant1' },\n      user: { id: 'user1' },\n      roles: ['member']\n    };\n    \n    await tenantContext.runAsync(memberContext, async () =\u003e {\n      await expect(deleteProject('project1')).rejects.toThrow('Insufficient permissions');\n    });\n  });\n});\n```\n\n\u003c/details\u003e\n\n---\n\n## 📊 Migration Guides\n\n### From Manual Multi-Tenancy\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eStep-by-step migration from custom solution\u003c/strong\u003e\u003c/summary\u003e\n\n**Before: Manual tenant filtering**\n```typescript\n// ❌ Before: Manual and error-prone\napp.get('/api/users', async (req, res) =\u003e {\n  const tenantId = req.headers['x-tenant-id']; // Manual extraction\n  if (!tenantId) return res.status(400).json({ error: 'Missing tenant' });\n  \n  const users = await prisma.user.findMany({\n    where: { tenantId: tenantId } // Manual filtering - easy to forget!\n  });\n  res.json(users);\n});\n```\n\n**After: Automatic with SaaS Toolkit**\n```typescript\n// ✅ After: Automatic and bulletproof\napp.use(createTenantMiddleware({ \n  resolution: { type: 'header', headerName: 'x-tenant-id' },\n  dataStore: tenantDataStore \n}));\n\napplyPrismaAdapter(prisma, {\n  tenantField: 'tenantId',\n  models: ['User'] // Automatic filtering\n});\n\napp.get('/api/users', async (req, res) =\u003e {\n  const users = await prisma.user.findMany(); // Automatically filtered!\n  res.json(users);\n});\n```\n\n**Migration steps:**\n1. Install the toolkit\n2. Replace manual tenant extraction with middleware\n3. Apply ORM adapters\n4. Remove manual filtering from queries\n5. Add role-based authorization\n6. Test thoroughly\n\n\u003c/details\u003e\n\n### From Other Multi-Tenancy Libraries\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eMigration guides for popular alternatives\u003c/strong\u003e\u003c/summary\u003e\n\n**From `@clerk/backend`:**\n```typescript\n// Before\nimport { clerkMiddleware } from '@clerk/backend';\napp.use(clerkMiddleware);\n\n// After: More control and flexibility\nimport { createTenantMiddleware } from '@saaskit/multitenancy-core';\napp.use(createTenantMiddleware({\n  resolution: { type: 'token', tokenClaim: 'org_id' },\n  dataStore: clerkTenantDataStore\n}));\n```\n\n**From `@casl/ability`:**\n```typescript\n// Before: Manual ability setup for each request\nconst ability = defineAbilityFor(user);\nif (ability.cannot('delete', 'Project')) {\n  throw new ForbiddenError();\n}\n\n// After: Automatic context-aware authorization\nimport { requirePermission } from '@saaskit/multitenancy-core';\napp.delete('/projects/:id', requirePermission('projects:delete'), handler);\n```\n\n\u003c/details\u003e\n\n---\n\n## 🎯 Production Checklist\n\nBefore going live, ensure you have:\n\n- [ ] **Tenant isolation tested** - Verify no data leakage between tenants\n- [ ] **Database indexes added** - Index all `tenantId` fields for performance  \n- [ ] **Error handling configured** - Proper error responses for invalid tenants\n- [ ] **Audit logging enabled** - Track all sensitive operations\n- [ ] **Rate limiting per tenant** - Prevent resource exhaustion\n- [ ] **Backup strategy** - Tenant-aware backup and restore\n- [ ] **Monitoring set up** - Track tenant-specific metrics\n- [ ] **Security review completed** - Regular security audits\n\n### Production Configuration\n\n```typescript\n// production.ts\nconst config = {\n  tenant: {\n    resolution: { type: 'subdomain' },\n    dataStore: new CachedTenantDataStore(redis, database),\n    allowNoTenant: false,\n    validateAccess: true,\n    onError: (error, req, res) =\u003e {\n      logger.error('Tenant resolution failed', { \n        error: error.message, \n        ip: req.ip,\n        userAgent: req.get('user-agent')\n      });\n      res.status(400).json({ error: 'Invalid tenant configuration' });\n    }\n  },\n  database: {\n    pooling: { max: 20, idleTimeout: 30000 },\n    caching: { enabled: true, ttl: 300 },\n    indexing: { autoCreate: false } // Create indexes manually in production\n  },\n  audit: {\n    enabled: true,\n    store: new DatabaseAuditStore(prisma),\n    retention: { days: 365 },\n    sensitive: ['password', 'apiKey', 'token', 'secret']\n  },\n  security: {\n    rateLimit: {\n      windowMs: 15 * 60 * 1000, // 15 minutes\n      max: 1000, // Per tenant\n      keyGenerator: (req) =\u003e `${req.tenant?.id}:${req.ip}`\n    }\n  }\n};\n```\n\n---\n\n## 📚 API Reference\n\n### Core Package\n\n#### `createTenantMiddleware(options: TenantMiddlewareOptions)`\nCreates middleware for automatic tenant resolution and context management.\n\n```typescript\ninterface TenantMiddlewareOptions {\n  resolution: TenantResolutionOptions;\n  dataStore: TenantDataStore;\n  onError?: (error: Error, req: any, res: any) =\u003e void;\n  allowNoTenant?: boolean;\n  validateAccess?: boolean;\n}\n```\n\n#### `tenantContext: TenantContextManager`\nSingleton for accessing current tenant context.\n\n```typescript\n// Get current tenant\nconst tenant = tenantContext.getCurrentTenant();\nconst tenantId = tenantContext.getCurrentTenantId();\n\n// Get current user and roles\nconst user = tenantContext.getCurrentUser();\nconst roles = tenantContext.getCurrentRoles();\nconst permissions = tenantContext.getCurrentPermissions();\n\n// Check permissions\nconst canEdit = tenantContext.hasPermission('projects:write');\nconst isAdmin = tenantContext.hasRole('admin');\n```\n\n#### Middleware Helpers\n\n```typescript\n// Require authentication\napp.use(requireTenantAuth);\n\n// Require specific roles (any of)\napp.use(requireRole('admin', 'moderator'));\n\n// Require specific permissions (any of)\napp.use(requirePermission('users:read', 'users:write'));\n```\n\n### Adapters Package\n\n#### Prisma Adapter\n\n```typescript\nimport { applyPrismaAdapter, createPrismaAdapter } from '@saaskit/multitenancy-adapters';\n\n// Apply to existing client\napplyPrismaAdapter(prisma, {\n  tenantField: 'tenantId',\n  models: ['User', 'Project'],\n  exclude: ['SystemLog'],\n  onViolation: 'throw' | 'warn' | 'ignore'\n});\n\n// Create new tenant-aware client\nconst TenantPrismaClient = createTenantPrismaClient(PrismaClient, options);\nconst prisma = new TenantPrismaClient();\n```\n\n#### Sequelize Adapter\n\n```typescript\nimport { applySequelizeAdapter, TenantModel } from '@saaskit/multitenancy-adapters';\n\n// Apply to specific model\napplySequelizeAdapter(User, {\n  tenantField: 'tenantId',\n  autoScope: true\n});\n\n// Use base model class\nclass User extends TenantModel {\n  // Your model definition\n}\n```\n\n#### Mongoose Adapter\n\n```typescript\nimport { mongooseTenantPlugin, createTenantModel } from '@saaskit/multitenancy-adapters';\n\n// Apply as plugin\nuserSchema.plugin(mongooseTenantPlugin, {\n  tenantField: 'tenantId',\n  indexTenant: true,\n  autoPopulate: false\n});\n\n// Create tenant-specific models\nconst TenantUser = createTenantModel(User, tenantId);\n```\n\n### Auth Package\n\n#### `RoleManager`\n\n```typescript\nconst roleManager = new RoleManager({\n  roles: RoleDefinition[],\n  permissionHierarchy: Record\u003cstring, string[]\u003e\n});\n\n// Role management\nroleManager.registerRole(role);\nroleManager.getRole(name);\nroleManager.getRolePermissions(roleName);\nroleManager.hasRole(name);\n\n// Permission management\nroleManager.setPermissionHierarchy(hierarchy);\nroleManager.addPermissionImplication(parent, children);\n```\n\n#### `PolicyEngine`\n\n```typescript\nconst policyEngine = new PolicyEngine();\n\n// Policy management\npolicyEngine.registerPolicy(policy);\npolicyEngine.registerPolicies(policies);\npolicyEngine.evaluate(context);\n\n// Policy templates\nPolicyEngine.createOwnershipPolicy(resourceType);\nPolicyEngine.createRolePolicy(role, actions, resources);\nPolicyEngine.createTimeBasedPolicy(id, name, actions, resources, startTime, endTime);\n```\n\n#### `AuthorizationManager`\n\n```typescript\nconst authManager = new AuthorizationManager({\n  roleManager,\n  policyEngine\n});\n\n// Authorization checks\nconst canAccess = await authManager.can(action, resource);\nconst cannotAccess = await authManager.cannot(action, resource);\n\n// Bulk checks\nconst permissions = await authManager.getPermissions(subject);\nconst roles = await authManager.getRoles(subject);\n```\n\n---\n\n## 🤝 Contributing\n\nWe love contributions! Here's how to get started:\n\n### Quick Setup\n\n```bash\n# Clone and setup\ngit clone https://github.com/saaskit/multitenancy.git\ncd multitenancy\nnpm install\n\n# Run tests\nnpm test\n\n# Build packages\nnpm run build\n\n# Try the example\ncd examples/express-demo\nnpm run dev\n```\n\n### Contribution Ideas\n\n- 🎯 **New adapters** - Add support for more ORMs/databases\n- 🔧 **Framework integrations** - Add support for Koa, Hapi, etc.\n- 📚 **Examples** - More real-world examples and tutorials\n- 🐛 **Bug fixes** - Check our [issues](https://github.com/saaskit/multitenancy/issues)\n- 📖 **Documentation** - Improve guides and API docs\n- ⚡ **Performance** - Optimize hot paths and memory usage\n\n### Development Guidelines\n\n- Write tests for new features\n- Follow TypeScript best practices\n- Update documentation\n- Add examples for new features\n- Ensure backward compatibility\n\n---\n\n## 📈 Roadmap\n\n### 🎯 Next Release (v2.0)\n- [ ] **GraphQL integration** - Schema stitching and resolvers\n- [ ] **Admin dashboard** - Web UI for tenant management\n- [ ] **Advanced caching** - Redis integration and cache invalidation\n- [ ] **Tenant analytics** - Usage metrics and insights\n- [ ] **Webhook system** - Event-driven tenant lifecycle\n\n### 🚀 Future Releases\n- [ ] **Python support** - Django and FastAPI adapters\n- [ ] **Multi-region** - Geographical tenant distribution\n- [ ] **Tenant migration** - Tools for moving tenants between databases\n- [ ] **Advanced RBAC** - Hierarchical roles and dynamic permissions\n- [ ] **Compliance tools** - GDPR, SOC2, HIPAA helpers\n\n### 💡 Community Requests\nVote on features at [our discussions](https://github.com/saaskit/multitenancy/discussions)!\n\n---\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n**Free for commercial use** ✅ **No attribution required** ✅ **Modify as needed** ✅\n\n---\n\n## 🆘 Support \u0026 Community\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e\n\u003cstrong\u003e📚 Documentation\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://docs.saaskit.dev\"\u003edocs.saaskit.dev\u003c/a\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\n\u003cstrong\u003e💬 Discord\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://discord.gg/saaskit\"\u003eJoin our community\u003c/a\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\n\u003cstrong\u003e🐛 Issues\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/saaskit/multitenancy/issues\"\u003eReport bugs\u003c/a\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\n\u003cstrong\u003e💡 Discussions\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/saaskit/multitenancy/discussions\"\u003eShare ideas\u003c/a\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Enterprise Support\n\nNeed help with production deployment, custom features, or architecture review?\n\n**📧 [enterprise@saaskit.dev](mailto:enterprise@saaskit.dev)**\n\nWe offer:\n- 🏗 **Architecture consulting** - Design review and best practices\n- ⚡ **Performance optimization** - Scale to millions of tenants\n- 🔒 **Security audits** - Comprehensive security review\n- 🎓 **Training** - Team training and workshops\n- 🛠 **Custom development** - Bespoke features and integrations\n\n---\n\n## ⭐ Show Your Support\n\nIf this toolkit saved you weeks of development time, give us a star! ⭐\n\nIt helps other developers discover the project and motivates us to keep improving it.\n\n[![GitHub stars](https://img.shields.io/github/stars/saaskit/multitenancy.svg?style=social\u0026label=Star)](https://github.com/saaskit/multitenancy)\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Built with ❤️ by the SaaSKit team**\n\n*Making multi-tenancy accessible to every developer*\n\n\u003c/div\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flanemc%2Fmulti-tenant-saas-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flanemc%2Fmulti-tenant-saas-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flanemc%2Fmulti-tenant-saas-toolkit/lists"}