Multi-Tenant Architecture: One App, Many Workspaces
JamCrew serves dozens of production companies from a single Next.js application. Each company gets its own subdomain (acme.jamcrew.io), its own branding, and its own data. But under the hood, they all share the same codebase, the same database, and the same deployment. This is multi-tenancy, and getting it right is one of the most consequential architectural decisions in a SaaS product.
Subdomain Routing
Every request to JamCrew starts in Next.js middleware. The middleware extracts the subdomain from the hostname, looks up the corresponding workspace in the database, and attaches the tenant context to the request. If the subdomain is "acme", the middleware resolves the Acme Productions workspace and every downstream component renders with Acme's data and branding. Reserved subdomains like "www", "app", and "api" are excluded from tenant resolution and serve the marketing site or API endpoints instead.
Vercel's wildcard domain configuration makes this possible at the infrastructure level. A single *.jamcrew.io record routes all subdomains to the same deployment. No DNS changes needed when a new company signs up.
Data Isolation
Data isolation is enforced at the access control level using TypeScript query and mutation wrappers in Convex. Every tenant-scoped table has a tenantId field, and our access control helpers ensure that queries only return rows belonging to the authenticated user's workspace. This is not optional filtering that could be bypassed by a bug. It is a structural constraint enforced by wrapper functions that every tenant-scoped query and mutation must use.
This approach means that a coding mistake in the application layer cannot leak data across tenants. Even if a developer writes a query without filtering, the access control wrapper adds the tenant constraint automatically. This defense-in-depth strategy is essential when handling sensitive crew data like pay rates, personal contact information, and work history.
Cross-Subdomain Authentication
Authentication cookies are set on the parent domain (.jamcrew.io) so they persist across subdomains. When a user logs in on acme.jamcrew.io, the session cookie is available on any other subdomain. This enables features like workspace switching without re-authentication and admin access to multiple workspaces from a single account.
Clerk handles authentication with JWT-based sessions. The middleware validates the session token on every request before resolving the tenant.
Workspace Branding
Each workspace stores branding configuration in the database: primary color, accent color, logo (light and dark variants), and an optional display font. When a tenant is resolved, these values are injected as CSS custom properties into the page. The platform chrome (navigation, tab bars, system UI) always uses JamCrew's default Midnight and Honey palette, but the workspace content area adapts to the company's branding. Color contrast is calculated automatically: if an admin picks a dark primary color, text flips to light.
Why Not Separate Databases?
Some multi-tenant architectures give each tenant their own database. This simplifies isolation but creates operational complexity: schema migrations must be applied to every database, monitoring multiplies, and resource utilization becomes uneven. For JamCrew's scale, a shared database with TypeScript-level access control provides strong isolation with minimal operational overhead. If a tenant's data grows large enough to warrant dedicated infrastructure, the tenantId field makes migration straightforward.
Ready to streamline your crew management?
JamCrew helps production companies manage crews, gigs, and schedules in one place.
Get Started