Implementing Multi‑Tenancy Scoping Across the VS API – A Step‑by‑Step Code Walkthrough A developer completed Phase 4 of a multi-tenancy migration for the VS API, a real-estate monolith that previously returned data across all organizations. The work scopes every data-access point to organization_id using a new TenantContext utility that extracts the tenant from any NestJS execution context, including HTTP requests and background jobs. Controllers and services were updated to pass the organization ID down rather than reading it from raw Request objects. TL;DR: I finished Phase 4 of the multi‑tenancy migration by scoping every data‑access point to organization id . The change lives in dozens of controllers/services construction, brokers, stats, etc. and required a handful of helper utilities to keep the code DRY and safe. Our monolithic VS API was built for a single tenant. When we started onboarding multiple real‑estate agencies, every endpoint returned data for all organizations, which broke privacy and caused massive performance regressions. The symptom showed up in the test suite: FAIL apps/api/src/ tests /stats.test.ts ✕ should return stats only for the requested organization 500 ms Expected: {"organizationId":"org 123","visits":42} Received: {"organizationId":"org 123","visits":42,"otherOrgVisits":17} The root cause: most controllers performed raw DB queries without filtering by organization id . The code base also mixed “global” services e.g., whatsapp-ai.service.ts with tenant‑specific logic, making it impossible to enforce isolation at runtime. My first attempt was to add a NestJS Guard that injected the tenant from the JWT and stored it in request.organizationId . I then tried to read that value inside each service: @Injectable export class StatsService { async getStats req: Request { const orgId = req 'organizationId' ; // <-- first try return this.db.stats.findMany { where: { organizationId: orgId } } ; } } Two problems surfaced quickly: @Req while others used the ExecutionContext directly, leading to undefined values. Request parameter just to fetch the tenant, polluting method signatures and making unit testing harder. The guard approach also failed to cover background jobs cron, queue workers that run outside an HTTP request. I introduced a tiny utility that extracts the tenant from any NestJS context HTTP, RPC, or custom . The file lives at apps/api/src/tenancy/tenant-context.ts : js // apps/api/src/tenancy/tenant-context.ts import { ExecutionContext } from '@nestjs/common'; import { Request } from 'express'; export class TenantContext { static getOrganizationId context: ExecutionContext : string { const http = context.switchToHttp ; const request = http.getRequest