Multi-Tenant Platform Concepts

Multi-Tenant Platform Concepts

Tenants

What is a tenant

A tenant represents a customer, workspace, or organization within your multi-tenant application. Each tenant has its own data, configuration, and branding, but all tenants share the same codebase and deployment.

Examples:

Tenant identification strategies

You can identify tenants using three approaches:

const hostname = request.headers.get('host');
const subdomain = hostname.split('.')[0]; // "tenant1"
// Map custom domain to tenant in database
const tenant = await db.tenant.findFirst({
  where: { customDomain: hostname },
});
const pathname = request.nextUrl.pathname;
const tenantSlug = pathname.split('/')[1]; // "tenant1"

Tenant data isolation

Multi-tenant applications must isolate data between tenants:

database.ts
const posts = await db.post.findMany({
  where: { tenantId: tenant.id },
});

Domains

Wildcard domains

Wildcard domains let you automatically serve all subdomains from a single Vercel project:

Requirements: Must use Vercel's nameservers (ns1.vercel-dns.com, ns2.vercel-dns.com)

Custom domains

Custom domains let tenants bring their own domain:

SSL certificate issuance

Vercel automatically issues SSL certificates for all domains using Let's Encrypt:

Domain verification

For domains already in use on Vercel, ownership verification is required:

  1. Add domain to your project
  2. Vercel generates a unique TXT record
  3. Tenant adds TXT record to their DNS
  4. Verify ownership via SDK or dashboard
  5. Certificate issues once verified

Routing

How Proxy resolves tenants

Next.js Proxy runs on every request before your pages render:

export async function proxy(request: NextRequest) {
  const hostname = request.headers.get('host');

// Get tenant from subdomain or custom domain
  const tenant = await resolveTenant(hostname);

// Forward tenant context to your app on the request headers
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-tenant-id', tenant.id);

return NextResponse.next({
    request: { headers: requestHeaders },
  });
}

Request handling flow

  1. User visits tenant1.yourapp.com
  2. Request hits Vercel's CDN
  3. Proxy extracts subdomain (tenant1)
  4. Proxy looks up tenant in database or Global Config
  5. Proxy adds tenant context to the request headers
  6. Page component reads tenant from headers
  7. Page renders with tenant-specific data

Performance considerations

import { get } from '@vercel/global-config';

const tenant = await get(`tenant_${hostname}`);

Architecture

Single deployment serving multiple domains

Multi-tenant architecture means:

Tenant context

Pass tenant information through your application:

const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-tenant-id', tenant.id);

return NextResponse.next({
  request: { headers: requestHeaders },
});
import { headers } from 'next/headers';

const headersList = await headers();
const tenantId = headersList.get('x-tenant-id');
const tenantId = request.headers.get('x-tenant-id');

Last updated August 20, 2026