typescriptadvanced

Multi-Tenant App with Subdomains

Build a multi-tenant application using middleware to resolve tenant from subdomain.

typescript
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const hostname = request.headers.get('host') || '';
  const currentHost = hostname.split(':')[0]; // Remove port

  // Define your root domain
  const rootDomain = process.env.ROOT_DOMAIN || 'example.com';

  // Skip for root domain and www
  if (currentHost === rootDomain || currentHost === `www.${rootDomain}`) {
    return NextResponse.next();
  }

  // Extract subdomain
  const subdomain = currentHost.replace(`.${rootDomain}`, '');

  // Rewrite to tenant-specific path
  const url = request.nextUrl.clone();
  url.pathname = `/tenant/${subdomain}${url.pathname}`;

  return NextResponse.rewrite(url);
}

// app/tenant/[domain]/page.tsx
async function getTenantConfig(domain: string) {
  // Fetch tenant config from database
  return {
    name: domain,
    theme: { primaryColor: '#3B82F6' },
    logo: `/tenants/${domain}/logo.png`,
  };
}

export default async function TenantHome({
  params,
}: {
  params: Promise<{ domain: string }>;
}) {
  const { domain } = await params;
  const config = await getTenantConfig(domain);

  return (
    <div>
      <h1>Welcome to {config.name}</h1>
      <p>Multi-tenant SaaS platform</p>
    </div>
  );
}

// app/tenant/[domain]/layout.tsx
export async function generateStaticParams() {
  const tenants = await getAllTenants();
  return tenants.map((t) => ({ domain: t.domain }));
}

Use Cases

  • SaaS platforms
  • white-label apps
  • customer portals

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.