Skip to content
Docs

Multi-Tenant Platform Concepts

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:

  • Blog platform: Each writer with their own blog is a tenant
  • Documentation platform: Each company with its own docs site is a tenant
  • E-commerce platform: Each store owner is a tenant

You can identify tenants using three approaches:

Subdomain-based: Extract the tenant from the subdomain (tenant1.yourapp.com)

proxy.ts
const hostname = request.headers.get('host');
const subdomain = hostname.split('.')[0]; // "tenant1"

Custom domain-based: Map custom domains to tenants (tenant1.com → Tenant 1)

proxy.ts
// Map custom domain to tenant in database
const tenant = await db.tenant.findFirst({
  where: { customDomain: hostname },
});

Path-based: Extract tenant from URL path (/tenant1/dashboard)

proxy.ts
const pathname = request.nextUrl.pathname;
const tenantSlug = pathname.split('/')[1]; // "tenant1"

Multi-tenant applications must isolate data between tenants:

Database-level: Use tenant ID in all queries

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

Application-level: Next.js Proxy ensures requests can only access their tenant's data

Global Config: Store tenant configuration for fast lookups at the edge

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

  • Add *.yourapp.com to your project
  • Point your domain to Edgenivo's nameservers
  • Any first-level subdomain (tenant1.yourapp.com, tenant2.yourapp.com) automatically routes to your app
  • Edgenivo issues one wildcard SSL certificate for *.yourapp.com that covers every first-level subdomain

Requirements: Edgenivo must be able to answer the DNS challenge for the wildcard certificate. Use Edgenivo's nameservers (ns1.vercel-dns.com, ns2.vercel-dns.com), or delegate certificate validation if you can't change nameservers.

Custom domains let tenants bring their own domain:

  • Add tenant1.com to your Edgenivo project via SDK
  • Tenant configures DNS (CNAME or nameservers)
  • Verify domain ownership (TXT record)
  • Edgenivo issues SSL certificate automatically

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

  • Wildcard domains: One wildcard certificate per wildcard domain, validated with a DNS challenge. *.yourapp.com covers tenant1.yourapp.com but not docs.tenant1.yourapp.com; add *.tenant1.yourapp.com for that level
  • Custom domains: Individual certificate per domain, validated with an HTTP challenge once the domain points to Edgenivo
  • Automatic renewal before expiration
  • No configuration required

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

  1. Add domain to your project
  2. Edgenivo 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

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

proxy.ts
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 },
  });
}
  1. User visits tenant1.yourapp.com
  2. Request hits Edgenivo'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

Global Config: Store tenant configuration at the edge for sub-10ms lookups

edge-config.ts
import { get } from '@vercel/global-config';
 
const tenant = await get(`tenant_${hostname}`);

Caching: Cache tenant lookups in the proxy to reduce database queries

Connection pooling: Use connection pooling for database queries to handle multiple tenants efficiently

Multi-tenant architecture means:

  • One Next.js codebase
  • One Edgenivo deployment
  • Multiple domains (subdomains + custom domains)
  • Shared infrastructure and resources
  • Tenant-aware routing and data access

Pass tenant information through your application:

In Proxy: Forward context on the request headers

proxy.ts
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-tenant-id', tenant.id);
 
return NextResponse.next({
  request: { headers: requestHeaders },
});

Use NextResponse.next({ request: { headers } }) to send the value to your app. Setting response.headers instead sends the header to the browser, where server components can't read it. Delete or overwrite inbound x-tenant-* headers on every path through the proxy so clients can't supply tenant context themselves.

In server components: Read headers

server-component.ts
import { headers } from 'next/headers';
 
const headersList = await headers();
const tenantId = headersList.get('x-tenant-id');

In API routes: Access request headers

api-route.ts
const tenantId = request.headers.get('x-tenant-id');
Last updated August 20, 2026

Was this helpful?

supported.