Skip to main content

Best Boilerplates for White-Label SaaS 2026

·StarterPick Team
Share:

TL;DR

White-label SaaS = multi-tenancy + per-tenant custom domains + per-tenant branding. The technical complexity is subdomain routing and DNS management. In 2026, Vercel Domains API + Next.js middleware is the standard for custom domain handling. Per-tenant branding (logo, colors, fonts) is solved with CSS variables in the database. Supastarter and Bedrock are the only two boilerplates with serious white-label support out-of-the-box.

Key Takeaways

  • Custom domains: Vercel Domains API (programmatic DNS management) or Cloudflare via API
  • Subdomain routing: Next.js middleware detects *.yourdomain.com → loads tenant config
  • Per-tenant branding: Store theme config in DB, inject as CSS variables at request time
  • DNS flow: Customer adds CNAME → Your API calls Vercel/Cloudflare API → Domain resolves
  • SSL: Automatic with Vercel custom domains; handled for you
  • Supastarter: Best pre-built white-label support with domain management UI

What Makes White-Label Different from Multi-Tenant

White-label SaaS is a specific flavor of multi-tenancy with two additional hard requirements: each tenant needs their own domain (not just a subdomain), and each tenant needs complete visual brand control. These two requirements add significant engineering complexity that general multi-tenant boilerplates don't address.

A standard multi-tenant boilerplate gives each customer a URL like acme.yourtool.com. White-label means the customer can point app.acme.com — their own domain — at your product and have it appear entirely as their branded experience. Their logo, their colors, their domain. No trace of your brand anywhere.

This is a powerful selling point for a specific type of SaaS: agency platforms, enterprise software that large customers want to present internally as their own tool, and marketplaces that white-label the selling experience for each merchant.

The technical challenges are:

  1. DNS management at runtime — you need to programmatically add domains to your hosting when customers submit them
  2. SSL certificate provisioning — each custom domain needs a TLS certificate
  3. Request routing — your Next.js app needs to detect which tenant a request belongs to based on the domain
  4. Brand isolation — each tenant needs completely different visual configuration

Best Boilerplates for White-Label SaaS

1. Supastarter

Supastarter is the most complete white-label starting point available in 2026. It ships with a domain management UI, the Vercel Domains API integration, per-tenant theme configuration, and the middleware routing logic.

What's included out of the box:

  • Custom domain management panel (add, verify, remove)
  • Vercel Domains API integration with domain verification status
  • Per-tenant branding: logo, colors, font, favicon
  • Next.js middleware for subdomain and custom domain routing
  • Team/organization multi-tenancy architecture

What you still need to build:

  • Customer onboarding flow (DNS instructions UX)
  • Domain verification email notifications
  • Billing model for white-label tiers (usually higher plan)

Price: $299 one-time. Given that the custom domain infrastructure alone takes 3–5 days to build correctly, this is almost always worth it.

Best for: Products where white-label is a core selling point and you want to move fast.

2. Bedrock

Bedrock (by Maximilian Kaske) includes white-label infrastructure as an optional module. Its subdomain routing is well-implemented and the team/workspace architecture maps cleanly to white-label use cases.

Differentiator: Bedrock has stronger opinionated defaults than Supastarter, which makes it faster to get to a working product but less flexible to customize.

Best for: Technical founders who want opinionated architecture and don't mind less flexibility.

Price: $249 one-time.

3. T3 Stack (DIY White-Label)

The T3 Stack doesn't include white-label out of the box, but it's the best foundation for building a custom white-label implementation when Supastarter's approach doesn't fit your product architecture.

The middleware pattern, Vercel Domains API integration, and CSS variable theming are all 1–2 day implementations if you already have T3 running. The advantage: you control every detail.

When to choose this: Your white-label requirements deviate from the standard pattern (e.g., you're not on Vercel, you need per-tenant custom code, or your domain routing logic is more complex than a CNAME setup).

4. ShipFast (Partial)

ShipFast doesn't ship with white-label support, but it's a popular choice for teams that add white-label as a feature post-launch. The codebase is clean enough to add the middleware routing and Vercel API integration on top without major surgery.

Time to add white-label to ShipFast: 3–5 days for a complete implementation including domain management UI.


Feature Comparison

BoilerplateCustom DomainsBrand ConfigDomain UISubdomainsPrice
Supastarter✅ Vercel API✅ Full✅ Built-in$299
Bedrock✅ Vercel API✅ Colors✅ Basic$249
T3 Stack❌ Build it❌ Build it❌ Build it❌ Build itFree
ShipFast❌ Build it❌ Build it❌ Build it❌ Build it$349
Makerkit✅ Supabase✅ Partial⚠️ Partial$299

The White-Label Architecture

Customer sets up:
  1. Add CNAME to their DNS: app.theirclient.com → your-vercel-app.vercel.app
  2. Submit domain in your dashboard

Your platform:
  1. Call Vercel Domains API to register domain
  2. Verify CNAME propagated
  3. Next.js middleware detects custom domain → loads tenant config
  4. Serve app with tenant's branding

Custom Domain Routing (Next.js + Vercel)

// middleware.ts — detect custom domains and subdomains:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  const hostname = request.headers.get('host') || '';
  const url = request.nextUrl;
  
  // Check if this is a custom domain or subdomain:
  const rootDomain = process.env.ROOT_DOMAIN!;  // yourdomain.com
  
  let tenantSlug: string | null = null;
  
  // 1. Custom domain (not yourdomain.com):
  if (!hostname.endsWith(`.${rootDomain}`) && hostname !== rootDomain) {
    // Look up tenant by custom domain:
    tenantSlug = await getTenantByDomain(hostname);
  }
  // 2. Subdomain (client.yourdomain.com):
  else if (hostname.endsWith(`.${rootDomain}`)) {
    tenantSlug = hostname.replace(`.${rootDomain}`, '');
  }
  
  if (tenantSlug) {
    // Rewrite URL to tenant-specific pages:
    return NextResponse.rewrite(new URL(`/tenant/${tenantSlug}${url.pathname}`, request.url));
  }
  
  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
// lib/domains.ts — Vercel Domains API integration:
const VERCEL_TOKEN = process.env.VERCEL_TOKEN!;
const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID!;
const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID;

export async function addCustomDomain(domain: string) {
  const response = await fetch(
    `https://api.vercel.com/v9/projects/${VERCEL_PROJECT_ID}/domains?${VERCEL_TEAM_ID ? `teamId=${VERCEL_TEAM_ID}` : ''}`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${VERCEL_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ name: domain }),
    }
  );
  
  const data = await response.json();
  
  if (!response.ok) {
    if (data.error?.code === 'domain_already_in_use') {
      throw new Error('Domain already in use by another project');
    }
    throw new Error(data.error?.message ?? 'Failed to add domain');
  }
  
  return data;
}

export async function removeDomain(domain: string) {
  await fetch(
    `https://api.vercel.com/v9/projects/${VERCEL_PROJECT_ID}/domains/${domain}`,
    {
      method: 'DELETE',
      headers: { Authorization: `Bearer ${VERCEL_TOKEN}` },
    }
  );
}

Per-Tenant Branding with CSS Variables

// Storing tenant theme in DB:
model TenantTheme {
  id              String @id @default(cuid())
  tenantId        String @unique
  primaryColor    String @default("#3b82f6")
  secondaryColor  String @default("#64748b")
  backgroundColor String @default("#ffffff")
  fontFamily      String @default("Inter")
  logoUrl         String?
  faviconUrl      String?
  borderRadius    String @default("0.5rem")
}
// app/tenant/[slug]/layout.tsx — inject theme:
import { getTenantTheme } from '@/lib/tenant';

export default async function TenantLayout({ params, children }) {
  const theme = await getTenantTheme(params.slug);
  
  const cssVariables = theme ? `
    :root {
      --color-primary: ${theme.primaryColor};
      --color-secondary: ${theme.secondaryColor};
      --color-background: ${theme.backgroundColor};
      --font-family: '${theme.fontFamily}', system-ui, sans-serif;
      --border-radius: ${theme.borderRadius};
    }
  ` : '';
  
  return (
    <html>
      <head>
        <style dangerouslySetInnerHTML={{ __html: cssVariables }} />
        {theme?.faviconUrl && <link rel="icon" href={theme.faviconUrl} />}
      </head>
      <body style={{ fontFamily: 'var(--font-family)' }}>
        {children}
      </body>
    </html>
  );
}

Domain Setup Flow for Customers

// app/api/tenant/domains/route.ts:
export async function POST(req: Request) {
  const { domain } = await req.json();
  const session = await auth();
  
  // Validate domain format:
  if (!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]\.[a-z]{2,}$/.test(domain)) {
    return Response.json({ error: 'Invalid domain format' }, { status: 400 });
  }
  
  // Check if domain is already taken:
  const existing = await db.tenant.findFirst({ where: { customDomain: domain } });
  if (existing && existing.id !== session!.tenantId) {
    return Response.json({ error: 'Domain already in use' }, { status: 409 });
  }
  
  // Register with Vercel:
  await addCustomDomain(domain);
  
  // Save to DB:
  await db.tenant.update({
    where: { id: session!.tenantId },
    data: { customDomain: domain, domainVerified: false },
  });
  
  // Return DNS instructions:
  return Response.json({
    cname: {
      type: 'CNAME',
      name: 'app',
      value: 'cname.vercel-dns.com',
    },
    instructions: 'Add this CNAME record to your DNS provider. Propagation takes 5–30 minutes.',
  });
}

Pricing White-Label Features: The Business Model

White-label capability is typically a premium tier feature. The standard SaaS pricing model separates white-label from the core product because it requires more infrastructure on your side (custom domain management, SSL per domain, per-tenant theming) and delivers significantly more value to customers who resell or present your product under their own brand.

Common pricing structures for white-label SaaS:

Feature-gated tiers: White-label is available on "Business" or "Enterprise" plans only. Standard and Professional plans use your brand. This is the most common approach — it keeps per-tenant infrastructure costs proportional to revenue.

Usage-based add-on: White-label is a flat add-on fee ($49–149/month) on top of any plan. This works well when most of your customers are agencies or resellers rather than end-users.

Flat enterprise pricing: If your entire product is designed around white-labeling (you sell a platform for agencies), custom domain support is the core feature and included in all paid plans.

The technical cost per white-label customer is roughly: Vercel custom domain registration (free), SSL certificate provisioning (free via Vercel), additional database row for tenant config (negligible), and increased middleware complexity (flat cost, already absorbed). The marginal cost per white-label tenant is near zero, which makes it a high-margin premium feature worth pricing aggressively.

White-Label vs Subdomain Architecture

Before implementing, decide whether customers get custom domains (true white-label) or subdomains (partial white-label). Subdomains are significantly easier to implement and still provide brand isolation:

Subdomain approach: acme-client.yourtool.com — Your brand is still visible in the URL, but customers can customize colors, logos, and the UI. Implementation: wildcard DNS (*.yourtool.com → your server), Next.js middleware parses the subdomain.

Custom domain approach: app.acme-client.com — Complete brand removal from the URL. Implementation: Vercel Domains API, customer sets CNAME, your middleware detects by domain. More complex, higher perceived value, justifies higher pricing.

Most SaaS products start with subdomains for their "Teams" plan and add custom domains for an "Enterprise" or "White-Label" plan. This staggers the technical complexity with the revenue that justifies it.


Common White-Label Gotchas

Caching conflicts between tenants. If you use Next.js route caching aggressively, you may inadvertently serve one tenant's cached page to another. Always include the tenant identifier in your cache keys. Use unstable_cache with tenant-scoped tags, not global ones.

Wildcard SSL certificates. A wildcard cert like *.yourdomain.com covers subdomains but not custom domains. Vercel handles per-domain SSL automatically, but if you're not on Vercel you'll need to provision certificates via Let's Encrypt (cert-manager in Kubernetes, or AWS Certificate Manager).

CNAME vs A record. Instructing customers to add a CNAME works for subdomains but not for apex domains (their root acme.com). For apex domains, many DNS providers support CNAME flattening (Cloudflare, Namecheap). Document this edge case in your onboarding flow.

Rate limits on Vercel Domains API. Vercel rate limits domain registrations. For high-volume scenarios (agency platforms with many clients), batch domain additions and implement a queue rather than adding domains synchronously on user request.


Choosing Your Approach

Choose Supastarter for white-label if:

  • Need pre-built domain management UI
  • Don't want to implement Vercel API integration yourself
  • React + Next.js stack
  • The $299 license saves 3–5 days of engineering

Build custom white-label on T3 or ShipFast if:

  • Need specific customization beyond the standard CNAME pattern
  • Not deploying on Vercel (AWS, Railway, Fly.io)
  • Have engineering bandwidth and want full control

White-label readiness checklist:

  • ✅ Vercel Domains API integration
  • ✅ Next.js middleware for domain routing
  • ✅ Per-tenant theme (CSS variables in DB)
  • ✅ Per-tenant logo/favicon
  • ✅ Subdomain routing (*.yourdomain.com)
  • ✅ DNS instructions for customers
  • ✅ Domain verification UI

Testing Multi-Tenant Isolation

White-label implementations are prone to a specific class of bugs: tenant data leaking across the wrong domain. A tenant sees another tenant's data, or a custom domain resolves to the wrong tenant's branding. These bugs are catastrophic from a trust and security perspective.

Build a testing checklist specifically for tenant isolation:

Domain routing tests: Programmatically verify that each registered custom domain resolves to the correct tenant config. If you have 50 white-label customers, automate a check that hits each domain and verifies the returned tenant ID matches the expected one.

Data isolation tests: For every database query in your application, verify it includes a tenant scoping clause. A query that returns all users without filtering by organizationId is a potential data leak. Use Prisma middleware to log queries missing tenant filters during development.

Brand isolation visual tests: Use Playwright to screenshot each tenant's app with the same user and verify the logo, colors, and font are unique per tenant. Catches cases where theme changes don't propagate correctly.

SSL certificate tests: After adding a new custom domain, automated tests should verify the SSL certificate is valid and issued for the correct domain before marking domain setup as complete.

Run these tests in your CI pipeline. Tenant isolation bugs discovered in production are orders of magnitude more damaging than discovery in testing.

Onboarding White-Label Customers

The technical implementation is one part of white-label SaaS; the customer onboarding experience is equally important. White-label customers are typically agencies or enterprise clients who are less technical than typical SaaS users — they need guided setup.

A good white-label onboarding flow:

  1. DNS instruction page: Clear, provider-agnostic instructions with specific DNS record values. Include screenshots for common DNS providers (Cloudflare, GoDaddy, Namecheap). Show expected propagation time.

  2. Domain verification status: Real-time status showing "Checking DNS propagation..." with clear success/failure states. Don't make customers open the terminal to verify — check it for them.

  3. Branding setup wizard: Step-by-step: upload logo → choose primary color → preview the result → save. A live preview showing how changes will look reduces iteration cycles.

  4. Test link before go-live: Provide a staging link (staging.yourdomain.com) to verify everything looks correct before cutting over the production DNS.

  5. Support escalation path: For DNS issues (the most common support ticket for white-label products), have a documented escalation path. DNS propagation problems are often on the customer's DNS provider side — your support team needs a script for the "I added the CNAME but it's not working" call.


For the full multi-tenant architecture foundation, see best boilerplates for multi-tenant SaaS. To compare Supastarter and Bedrock directly, see the Bedrock vs Supastarter comparison. If you're adding white-label to an existing app rather than starting fresh, the how to add multi-tenancy to a boilerplate guide walks through the incremental implementation.


Methodology

Boilerplate features verified against official documentation and GitHub repositories as of Q1 2026. Vercel Domains API behavior based on Vercel platform documentation. Pricing sourced from official product pages. Custom domain provisioning has become meaningfully easier with Vercel's improved Domains API and Cloudflare's automatic certificate issuance — teams implementing white-label features today face fewer infrastructure hurdles than those who tackled this problem in 2023.

Find white-label SaaS boilerplates at StarterPick.

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.