---
title: "Multi-tenant SaaS with Next.js: from template to production"
description: "Custom domain, per-tenant data isolation, billing integration, and feature flags. Our reference Next.js app-router stack that scales to 10k tenants."
date: 2026-03-10
updated: 2026-03-10
author: "Dezső Mező"
tags: "Web, SaaS, Next.js, Multi-tenant"
slug: multi-tenant-saas-nextjs-en
canonical: https://dfieldsolutions.com/blog/multi-tenant-saas-nextjs-en
---

# Multi-tenant SaaS with Next.js: from template to production

A multi-tenant Next.js SaaS reference from 2026: custom domains, RLS, per-tenant feature flags, and billing. No hand-waving.
Past ~10 tenants, multi-tenant architecture isn't a luxury · it's survival. Here's the reference stack we run on [Next.js](https://nextjs.org/docs/app) with [Postgres Row-Level Security](https://www.postgresql.org/docs/current/ddl-rowsecurity.html). We ship this under our [Web service](/services/web).

## 1. Tenant detection: subdomain vs custom domain

Subdomain (acme.app.com) is the default. Custom domain (app.acme.com) ships in the Growth plan. Next.js middleware resolves the tenant and attaches it to the request.

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

export async function middleware(req: NextRequest) {
  const host = req.headers.get("host") || "";
  const subdomain = host.replace(/\.app\.com$/, "");
  const tenant = await resolveTenantBySubdomain(subdomain);
  if (!tenant) return NextResponse.redirect(new URL("/404", req.url));

  const res = NextResponse.next();
  res.headers.set("x-tenant-id", tenant.id);
  return res;
}
```

## 2. Data isolation: Row-Level Security vs schema-per-tenant

Postgres RLS (PolicyScope) works well up to ~500 tenants. Above that, schema-per-tenant (or cluster-per-tenant for big customers). We default to RLS, and give dedicated schemas to critical accounts.

## 3. Per-tenant feature flags

Growth sees different features than Enterprise. We don't do if-elseif for this · PostHog feature flags + tenant group. The code stays clean.

## 4. Billing: Stripe + per-seat + usage

- Stripe Subscription per tenant; customer = tenant.
- Metered billing for usage-based products.
- Webhook → Postgres → cache invalidation.

## 5. Background jobs per tenant

Don't run tenant jobs in one global queue. BullMQ per-tenant queues or a Temporal namespace. A noisy tenant then can't tip the rest over.

## Summary

This architecture stands up in 2-8 weeks. If you're starting a SaaS today, start multi-tenant · retrofitting is always more expensive.

---

Source: https://dfieldsolutions.com/blog/multi-tenant-saas-nextjs-en
Author: Dezső Mező · Founder, DField Solutions
Site: https://dfieldsolutions.com
