Build Scalable Next.js SaaS Apps with Subdomain Multi-Tenancy

npmixnpmix
102
Nextjs Dynamic Imports

What is Multi-Tenant Architecture?

Multi-tenancy is a software architecture where a single instance of an application serves multiple tenants (customers or users). Each tenant's data is logically isolated, ensuring privacy and security while sharing the same infrastructure. This model is widely used in SaaS platforms like Salesforce, Google Workspace, and Dropbox.

Key Features of Multi-Tenancy

  • Shared Infrastructure: Tenants share the same hardware and software resources.
  • Tenant Isolation: Data and configurations are isolated for each tenant.
  • Cost Efficiency: Shared resources reduce costs compared to single-tenant setups.
  • Scalability: Easily accommodates more tenants by leveraging shared resources.

Building a Multi-Tenant Application with Next.js

This guide demonstrates how to build a multi-tenant application using Next.js with subdomain-based tenant separation, like tenant1.yourdomain.com, tenant2.yourdomain.com, etc.

🧪 Live Demo · View Source Code

Folder Structure

Organize your project like so:

bash
1├── app/
2│   ├── [subdomain]/     # Tenant-specific routes
3│   │   ├── page.tsx     # Main page for the tenant
4│   │   └── layout.tsx   # Layout wrapper for each tenant
5│   └── middleware.ts    # Middleware for subdomain handling
6├── public/
7│   └── images/tenant1/  # Static assets per tenant
8├── package.json         # Project config
9├── .env                 # Environment variables

Creating Middleware for Subdomain Routing

The middleware identifies tenants from the subdomain, handles auth, and rewrites routes dynamically.

ts
1import { NextResponse } from "next/server";
2import type { NextRequest } from "next/server";
3import { domain } from "@/lib/env";
4
5export function middleware(request: NextRequest) {
6  const hostname = request.headers.get("host") || "";
7  const url = request.nextUrl.clone();
8  const tenantSlug = hostname.split(".")[0];
9
10  if (hostname === domain || hostname === domain.split(":")[0]) {
11    return NextResponse.redirect(new URL(`http://login.${domain}`));
12  }
13
14  if (tenantSlug === "login") {
15    if (url.pathname !== "/" && url.pathname !== "/api/login") {
16      return NextResponse.redirect(new URL("/", request.url));
17    }
18    return NextResponse.next();
19  }
20
21  const userId = request.cookies.get("userId")?.value;
22  if (!userId && tenantSlug !== "login") {
23    return NextResponse.redirect(new URL(`http://login.${domain}/`, request.url));
24  }
25
26  url.pathname = `/${tenantSlug}${url.pathname}`;
27  return NextResponse.rewrite(url);
28}
29
30export const config = {
31  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
32};

How the Middleware Works

  • Subdomain Detection: Extracts the subdomain from the Host header.
  • Authentication: Redirects unauthenticated users to login.yourdomain.com.
  • Route Rewriting: Rewrites the request to target app/[subdomain]/.
  • Cookie Management: Uses a cookie (userId) for simple auth handling.

Implementation Steps

1. Configure Domains

Point both your root domain and subdomains to the same server.

2. Environment Variables

Define your domain in .env:

env
1DOMAIN=yourdomain.com

3. Local Development

Use local DNS mapping (e.g., /etc/hosts) to simulate subdomains:

bash
1127.0.0.1 login.localhost tenant1.localhost tenant2.localhost

4. Authentication Flow

Create a login page on the login subdomain. Upon successful login, set a userId cookie.

⚠️ Note: In practice, JWTs or secure cookies should be used. Since cross-domain cookies can be problematic, you may pass tokens via query params as a fallback.

5. Tenant-Specific Pages

Build tenant-specific components inside the app/[subdomain]/ directory.

Why Use This Pattern?

  • Scalability: Add new tenants simply by adding folders.
  • Isolation: Subdomain routing provides clean namespace separation.
  • Flexibility: Middleware allows fine-grained control over auth and routing logic.

Limitations & Caveats

🧠 This approach is based on a personal project and is not a full production-ready solution.

For robust cross-subdomain authentication and domain aliasing, consult more comprehensive guides or frameworks tailored for SaaS.

Reference


Have feedback or want to contribute? Reach out on GitHub or share this post with someone building a SaaS product.

Similar articles

Never miss an update

Subscribe to receive news and special offers.

By subscribing you agree to our Privacy Policy.