Multi-Tenant Template

Build SaaS applications that serve multiple domains from a single Next.js codebase

Multi-tenant applications allow you to serve different customers with unique domains from a single codebase. This template demonstrates how to build a platform that dynamically routes requests based on the incoming domain, enabling you to create white-label solutions, SaaS platforms, and marketplace applications.

Multi-Tenant Architecture

What is Multi-Tenancy?

Multi-tenancy is an architecture pattern where a single instance of an application serves multiple tenants (customers or organizations). Each tenant gets their own subdomain or custom domain while sharing the same underlying infrastructure and codebase.

Common use cases include:

  • White-label platforms - Rebrandable applications for different clients
  • SaaS marketplaces - Multiple stores/sites under one platform
  • Content management systems - Publishing platforms with custom domains
  • Agency portfolios - Client websites managed from one codebase

How It Works

The multi-tenant template uses Next.js middleware to intercept incoming requests and route them based on the hostname:

  1. Request arrives - A user visits customer1.example.com or customer1.com
  2. Middleware intercepts - Extracts the hostname from the request headers
  3. Dynamic routing - Rewrites the URL internally to include tenant context
  4. Tenant-specific content - Renders customized content for that domain
  5. Response served - User sees their branded experience

Getting Started

Step 1: Clone the Template

Start by cloning the multi-tenant template:

Terminal
git clone https://github.com/vercel/platforms
cd platforms
pnpm install

The template includes:

  • Next.js App Router for modern React architecture
  • Middleware for domain-based routing
  • Tailwind CSS for styling
  • TypeScript for type safety

Step 2: Set Up Local Development

For local development, you'll need to map custom domains to localhost. Add these entries to your hosts file:

/etc/hosts
127.0.0.1 tenant1.localhost
127.0.0.1 tenant2.localhost
127.0.0.1 custom.localhost

Then start the development server:

Terminal
pnpm dev

Visit different domains to see tenant-specific content:

Step 3: Configure Middleware

The middleware is the heart of the multi-tenant system. It intercepts all requests and routes them appropriately:

middleware.ts
import { type NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  const hostname = request.headers.get("host") || "";
  // Add tenant context to the request and rewrite to /[domain]

  // if it starts with /domains, pass through
  if (request.nextUrl.pathname.startsWith("/domains")) {
    return NextResponse.next();
  }

  const target = `${request.nextUrl.href}domains/${hostname}`;
  const response = NextResponse.rewrite(target);
  response.headers.set("x-tenant-domain", hostname);
  return response;
}

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

Step 4: Create Tenant-Specific Pages

Each tenant's content is served from a dynamic route that receives the domain as a parameter:

app/domains/[domain]/page.tsx
export default async function TenantPage({
  params,
}: {
  params: Promise<{ domain: string }>;
}) {
  const { domain } = await params;

  // Fetch tenant-specific data
  const tenant = await getTenantByDomain(domain);

  // Render customized content
  return (
    <div className="min-h-screen">
      <header className="p-6" style={{ backgroundColor: tenant.brandColor }}>
        <h1 className="text-3xl font-bold text-white">
          {tenant.name}
        </h1>
      </header>

      <main className="p-6">
        {/* Tenant-specific content */}
        <TenantContent data={tenant.content} />
      </main>
    </div>
  );
}

Core Components

Domain Resolution

The system identifies tenants through their domain:

middleware.ts
function extractSubdomain(request: NextRequest): string | null {
  const url = request.url;
  const host = request.headers.get('host') || '';
  const hostname = host.split(':')[0];

  // Local development environment
  if (url.includes('localhost') || url.includes('127.0.0.1')) {
    // Try to extract subdomain from the full URL
    const fullUrlMatch = url.match(/http:\/\/([^.]+)\.localhost/);
    if (fullUrlMatch && fullUrlMatch[1]) {
      return fullUrlMatch[1];
    }

    // Fallback to host header approach
    if (hostname.includes('.localhost')) {
      return hostname.split('.')[0];
    }

    return null;
  }

  // Production environment
  const rootDomainFormatted = rootDomain.split(':')[0];

  // Handle preview deployment URLs (tenant---branch-name.vercel.app)
  if (hostname.includes('---') && hostname.endsWith('.vercel.app')) {
    const parts = hostname.split('---');
    return parts.length > 0 ? parts[0] : null;
  }

  // Regular subdomain detection
  const isSubdomain =
    hostname !== rootDomainFormatted &&
    hostname !== `www.${rootDomainFormatted}` &&
    hostname.endsWith(`.${rootDomainFormatted}`);

  return isSubdomain ? hostname.replace(`.${rootDomainFormatted}`, '') : null;
}

Domain Configuration

Configure domains in your Vercel dashboard:

  1. Wildcard subdomain - *.yourdomain.com

    • Captures all subdomains automatically
    • Perfect for user-generated sites
  2. Custom domains - Add individually

    • Each tenant's custom domain
    • Requires DNS configuration per domain

Use Cases

SaaS Platforms

Build software that serves multiple organizations with isolated data and custom branding.

E-commerce Marketplaces

Create platforms where vendors get their own storefronts with unique domains.

Content Publishing

Enable creators to publish content on their custom domains while using your platform.

Agency Solutions

Manage multiple client websites from a single codebase with individual customizations.


The multi-tenant template provides a solid foundation for building platforms that serve multiple customers from a single codebase. By leveraging Next.js middleware and dynamic routing, you can create scalable SaaS applications that offer custom domains, personalized experiences, and efficient resource utilization.

Whether you're building a white-label solution, a marketplace platform, or a content management system, this architecture pattern enables you to grow from one to thousands of tenants without infrastructure complexity.