Back

Multi-Tenant SaaS Template Guide: Architecture, Databases, and Custom Domains

MM
MVPHub
11 min read

Multi-Tenant SaaS Template Guide: Architecture, Databases, and Custom Domains

Multi-tenant SaaS is one of those topics where "just use Prisma" glosses over the hardest decisions. The tenancy model you pick — database-per-tenant, shared-schema with row-level isolation, schema-per-tenant — shapes every subsequent architectural choice, and getting it wrong costs months of rework.

This guide walks through the real decision points, using a production booking-platform template as the concrete case study. By the end you should know which model fits your product, how to resolve tenants from incoming requests, how to handle custom domains, and which trade-offs you can safely ignore at launch versus the ones that will break you at scale.


TL;DR

  • Multi-tenant SaaS = one codebase serving many customers, each with isolated data, branding, and (often) custom domains.
  • Three tenancy models: shared schema, schema-per-tenant, database-per-tenant. Each has a specific sweet spot.
  • Database-per-tenant is the safest default for B2B SaaS where customers care about data isolation.
  • Host-aware routing (tenant from request host) is preferable to tenant-in-URL for custom domain support.
  • Control plane + tenant plane is the right architectural split for anything beyond a toy.

Browse booking platform templates to see this architecture in action.


What "multi-tenant" actually means

A multi-tenant SaaS is one codebase that serves multiple customers (tenants) from a shared deployment. The user-facing product looks branded to each tenant — custom colors, custom domain, custom content — but the underlying code is the same for everyone.

This is the default shape of most B2B SaaS (Slack, Notion, Intercom, Calendly). It's the opposite of "single-tenant" deployments where each customer gets their own copy of the application.

Multi-tenancy is attractive because:

  • One deployment to maintain — patches, upgrades, and features ship to everyone at once
  • Economies of scale — infrastructure cost per tenant decreases as you add more
  • Easier customer onboarding — new tenants provision through a signup flow, not a deploy

The cost is complexity: you have to get tenant isolation, routing, and provisioning right from the start, and "right" is not obvious.


The three tenancy models

1. Shared schema (row-level isolation)

How it works. One database, one set of tables. Every row has a tenantId column. Every query includes WHERE tenantId = $currentTenant — either through an ORM scope, a Postgres Row Level Security (RLS) policy, or developer discipline.

Pros.

  • Cheapest infrastructure — one database
  • Simplest migrations — change the schema once, all tenants get it
  • Easiest to run aggregate queries across tenants (analytics, admin views)

Cons.

  • Data isolation is a code-level concern, not an infrastructure one. A forgotten WHERE clause leaks data across tenants.
  • Noisy neighbors — one tenant's heavy queries affect everyone else
  • Hard to give one tenant a custom schema (e.g. "enterprise tenant wants custom fields")
  • Impossible to move one tenant's data to a dedicated database later without surgery

When to use it. Early-stage consumer SaaS where data isolation risks are low, tenants are small, and you need to keep infrastructure cost near zero.

2. Schema-per-tenant

How it works. One database, but each tenant has its own Postgres schema (tenant_acme, tenant_globex, etc.). Queries are scoped to a schema by setting search_path at the start of each connection.

Pros.

  • Better data isolation than shared schema
  • Tenant-specific schema changes are possible
  • Cross-tenant queries still work from the public schema

Cons.

  • Migrations become painful — running a schema change across 1000 tenant schemas is slow
  • Connection pooling is tricky — each pooled connection needs to reset search_path per query
  • Backup/restore granularity is per-database, not per-schema, so you can't easily pull one tenant's data
  • Postgres doesn't love having thousands of schemas — it works but metadata queries slow down

When to use it. Middle-ground cases where you want more isolation than shared schema but the ops overhead of database-per-tenant is too high. In practice, few teams land here long-term.

3. Database-per-tenant

How it works. Each tenant gets its own Postgres database. A control-plane database stores the tenant registry, and the application resolves the tenant database for each request.

Pros.

  • True data isolation — a bug can't leak data across tenants; they're physically separated
  • Per-tenant operations — backup, restore, export, compliance requests are all surgical
  • Resource isolation — noisy tenants don't affect others (especially with per-tenant connection pools)
  • Scales horizontally — you can move a tenant's database to its own server without migrating the rest of the fleet
  • Custom schemas per tenant are easy — run different migration sets

Cons.

  • Higher infrastructure cost — a database per tenant adds up
  • Migrations need orchestration — you're applying schema changes to N databases instead of one
  • Connection management is harder — you need a per-tenant connection pool strategy

When to use it. B2B SaaS where customers care about data isolation (most do), compliance matters (healthcare, finance, anything with GDPR/HIPAA scope), or you're planning to offer enterprise tiers with data residency guarantees.

This is the model MVPHub's booking platform template uses, and it's the model most production B2B SaaS converges on.


The control plane / tenant plane split

Once you're past the tenancy model decision, the next big architectural question is how to split your application between control plane concerns (cross-tenant) and tenant plane concerns (scoped to a specific tenant).

Control plane responsibilities:

  • Tenant registry (who's a customer, what plan they're on)
  • User-to-tenant memberships
  • Authentication for platform operators
  • Tenant provisioning and deprovisioning
  • Domain verification and custom domain management
  • Audit logs across tenants
  • Billing and subscription management
  • Platform-wide analytics

Tenant plane responsibilities:

  • Everything your customers' customers use — products, orders, bookings, content
  • Tenant-specific configuration and branding
  • Tenant-specific users and permissions
  • Tenant-specific business logic (services, schedules, inventory, whatever)

In a database-per-tenant model, this split maps cleanly to two database concerns:

  • Control plane database — holds tenants, memberships, domains, audits, billing
  • Tenant databases — one per tenant, holds everything tenant-specific

This is exactly the structure of the BookEase booking platform template: one control plane Prisma schema (packages/db/prisma/control), one tenant Prisma schema (packages/db/prisma/tenant), and orchestration code in the backend that resolves tenant connections per request.


Host-aware routing (resolving the current tenant)

Now you have a tenant model and a control/tenant plane split. The next question: how does a given HTTP request know which tenant it's for?

Three common patterns:

1. Tenant in URL path (/t/acme/...)

Pros. Simple to implement. No DNS work needed.
Cons. Tenant IDs visible in every URL — looks like a toy. Custom domains require rewrites. Shareable links expose tenant IDs.

2. Tenant in subdomain (acme.myapp.com)

Pros. Cleaner URLs. Easier to think about. Doesn't expose tenant IDs in the path.
Cons. Requires wildcard DNS. TLS certificates need to cover *.myapp.com (wildcard cert). Doesn't directly support customer custom domains.

3. Host-aware routing (request host is the tenant identifier)

Pros. Supports custom domains natively (acme.com → tenant acme). No tenant IDs in URLs at all. Feels like a standalone product to each tenant's users.
Cons. Requires a custom domain verification flow. TLS certificates need to be provisioned per custom domain (Let's Encrypt + Caddy, or platform-managed).

This is the pattern production multi-tenant SaaS converges on. It's also the one the BookEase template uses: a BFF (Backend-for-Frontend) layer reads the Host header on every request, looks up the tenant in the control plane, attaches the tenant context to the request, and pushes all UI rendering through server components that have access to tenant-specific data.


Custom domains (the hard part nobody warns you about)

Letting tenants use their own domain (booking.acmehair.com instead of acmehair.bookease.com) is a feature customers will ask for by year 1. It's also one of the trickier parts of multi-tenant SaaS because it touches DNS, TLS, and routing simultaneously.

The full flow

  1. Tenant enters custom domain in your admin UI (booking.acmehair.com)
  2. Your platform displays a DNS record for them to add (usually a CNAME to tenants.myapp.com)
  3. Tenant adds the record to their DNS provider
  4. Your platform verifies the record resolves correctly
  5. TLS certificate is provisioned — either via Let's Encrypt (HTTP-01 or DNS-01 challenge) or via a platform-managed cert (Vercel, Cloudflare)
  6. Host lookup — when requests arrive at booking.acmehair.com, your routing layer resolves them to the right tenant

Things that will break

  • DNS propagation delays — tenants add a CNAME, then refresh 10 seconds later and wonder why it isn't working. Build UI that tells them DNS takes minutes, not seconds.
  • CNAME flattening on apex domains — some providers (Route 53, Cloudflare) flatten apex CNAMEs, others don't. Document which root domains are allowed.
  • Certificate rate limits — Let's Encrypt has rate limits. Batching verifications matters once you have hundreds of domains.
  • HTTP to HTTPS redirects — handle this at the edge, not in the application.
  • Local development — you can't actually use custom domains locally. Use localtest.me (resolves any subdomain to localhost) for host-aware development.

Platform help

If your deployment target is Vercel or Cloudflare, both offer managed custom domain support through their APIs. It's not free — Vercel charges per domain, Cloudflare SaaS requires Business or Enterprise — but it removes most of the TLS and DNS pain.


How the booking template handles all of this

The BookEase template in the /verticals/booking collection implements all of the above:

  • Database-per-tenant with separate Prisma schemas for control and tenant data
  • Control plane handling tenant registry, memberships, domains, and audits
  • Tenant plane handling services, staff, schedules, appointments, and bookings
  • Host-aware routing via a Fastify BFF that resolves tenants from the request host
  • Custom domains with verification flow and tenant admin UI
  • Localtest.me based development for host-aware testing without DNS
  • Demo tooling (reset, seed, verify) for running deterministic QA across multiple tenants

The reference implementation is tuned for salons and spas but the core architecture is generic — you can adapt it to any appointment-based service (fitness studios, wellness clinics, repair shops, tutoring businesses).


Common mistakes

Starting with shared schema and planning to migrate later. In theory this is the lean startup approach. In practice, the migration is brutal once you have real customers and it never happens.

Hard-coding the tenant ID into URL paths. Leaks tenant identity, makes custom domains harder, looks amateur. Use host-aware routing from day one if you're serious about B2B.

Skipping the control plane. Trying to track tenants, memberships, and domains inside a tenant database creates circular dependencies and data duplication. The control/tenant split is not optional once you're past 10 tenants.

Forgetting about the admin dashboard. Platform operators need a way to onboard, audit, suspend, and support tenants. Build the control plane UI from day one — it's not a "nice to have."

Testing with only one tenant. Multi-tenant bugs hide until you have at least 3-5 tenants with different data shapes. Seed test environments with realistic multi-tenant data before you trust your isolation code.


Decision tree

Are you building B2B SaaS where customers care about data isolation?
→ Database-per-tenant. Start with the booking template as a reference.

Are you building consumer SaaS with thousands of tiny tenants?
→ Shared schema with RLS. Lighter infrastructure, acceptable isolation.

Are you in healthcare, finance, or anywhere with hard compliance requirements?
→ Database-per-tenant, full stop. Compliance auditors will ask.

Will customers want custom domains?
→ Host-aware routing from day one. Don't retrofit it.

Will you offer enterprise tiers later?
→ Database-per-tenant, because enterprises will ask for data residency, dedicated backups, or single-tenant deployments.


Next steps

Multi-tenant SaaS is a long game. Pick a tenancy model that matches your customer base, split your control plane from your tenant plane from day one, and use host-aware routing so custom domains are easy when customers ask for them. Get the foundations right and the rest of the work becomes feature development — not architecture rescue.

Working products with full source code — live demo, one-time purchase, instant delivery.

Browse the marketplace
GR LIVEecommerce

Groover Multi-Purpose Store

$149

A fully-polished, multi-purpose e-commerce template engineered for brands that need the full feature set on day one — not a minimal starter you outgrow in a month. Groover ships with a live Medusa-backed catalog, category + collection merchandising, search with multi-facet filtering (category, collection, price, sale, stock, sort), product-detail with variant selection + image gallery + stock messaging + related products, Stripe Elements checkout with provider-aware setup panels, account dashboard with guest order lookup and authenticated order history, customer auth with login/register/logout/profile edit, wishlist with guest browser persistence and signed-in customer sync, blog list + detail, store directory, track-order page, branded 404, About/Contact/FAQ/Terms legal shell, GTM-friendly dataLayer wired into PDP/cards/wishlist/cart/checkout/search, locale + RTL foundation with persistent language switcher, PWA installability baseline, theme switching that applies before hydration and persists in both local storage and cookies, header active-route navigation with live mini-cart summary, skip-link / focus accessibility basics, app-level and route-level loading fallbacks, a recoverable error boundary, generated robots.txt and sitemap.xml, shared SEO metadata helpers, and a Playwright / Vitest / Lighthouse test harness. Every copy string lives in a typed content map so rebranding is a find-and-replace pass, not a code rewrite. Deploy it as-is or use it as the most complete starting point you can buy for a serious storefront.

★★★★★0 soldAstro · Medusa
FU LIVEecommerce

Furniture Store

$49

An elegant furniture and home furnishing e-commerce app with a design-forward Next.js storefront for SEO-optimized product pages and server-rendered category browsing. Alternative framework and mobile ports are available on demand. The visual design emphasizes large product imagery, room-based browsing, and material/color variant selection. Built with Radix UI, shadcn/ui, Tailwind CSS, and Framer Motion for a premium feel. Connects to any headless commerce backend — Medusa JS SDK integration is included. Form handling via React Hook Form with Zod validation ensures robust checkout and account flows. Great for furniture brands, interior design shops, or home decor marketplaces.

★★★★★0 soldExpo · Next.js
PE LIVEecommerce

Perfume Store

$49

A luxury-styled perfume and fragrance e-commerce app built for premium brand presentation. The ready-to-buy Next.js storefront features rich product pages with scent profiles, bottle size variants, gift set options, and server-rendered collections. Mobile, backend, and alternative framework ports are available on demand. The design uses shadcn/ui and Tailwind CSS with an elegant, minimalist aesthetic suited for luxury goods. Easy to customize — swap product data, update branding, and deploy. Perfect for perfume brands, fragrance boutiques, or niche scent marketplaces.

★★★★★0 soldMedusa · Expo

Keep reading — popular SaaS guides on MVPHub.

All SaaS articles

Explore other MVP verticals

MVPHub publishes templates and guides for ecommerce, SaaS, marketplaces, AI apps, booking platforms, subscription stores, directory sites, and more. Here are fresh picks from other verticals.