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


Never miss an update
Subscribe to receive news and special offers.
By subscribing you agree to our Privacy Policy.
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.
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.
Organize your project like so:
βββ app/
β βββ [subdomain]/ # Tenant-specific routes
β β βββ page.tsx # Main page for the tenant
β β βββ layout.tsx # Layout wrapper for each tenant
β βββ middleware.ts # Middleware for subdomain handling
βββ public/
β βββ images/tenant1/ # Static assets per tenant
βββ package.json # Project config
βββ .env # Environment variablesThe middleware identifies tenants from the subdomain, handles auth, and rewrites routes dynamically.
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { domain } from "@/lib/env";
export function middleware(request: NextRequest) {
const hostname = request.headers.get("host") || "";
const url = request.nextUrl.clone();
const tenantSlug = hostname.split(".")[0];
if (hostname === domain || hostname === domain.split(":")[0]) {
return NextResponse.redirect(new URL(`http://login.${domain}`));
}
if (tenantSlug === "login") {
if (url.pathname !== "/" && url.pathname !== "/api/login") {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
}
const userId = request.cookies.get("userId")?.value;
if (!userId && tenantSlug !== "login") {
return NextResponse.redirect(new URL(`http://login.${domain}/`, request.url));
}
url.pathname = `/${tenantSlug}${url.pathname}`;
return NextResponse.rewrite(url);
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};Host header.login.yourdomain.com.app/[subdomain]/.userId) for simple auth handling.Point both your root domain and subdomains to the same server.
Define your domain in .env:
DOMAIN=yourdomain.comUse local DNS mapping (e.g., /etc/hosts) to simulate subdomains:
127.0.0.1 login.localhost tenant1.localhost tenant2.localhostCreate 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.
Build tenant-specific components inside the app/[subdomain]/ directory.
π§ 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.
Have feedback or want to contribute? Reach out on GitHub or share this post with someone building a SaaS product.