multi-tenant-architecture
Provides architecture guidance for multi-tenant SaaS platforms on Cloudflare or Vercel. Covers platform choice, domain strategy, tenant identification and isolation, subdomain routing, custom domains and SSL, white-label setup, tenant context propagation, PSL submission, and mapping platform limits to pricing plans. Use when building a multi-tenant application or asking "how do I support multiple tenants", "build a white-label platform", "add custom domains", "route tenants by subdomain", or "map limits to plans". For general app folder structure use define-architecture; for scaffolding a new Next.js repo use scaffold-nextjs.
How do I install this agent skill?
npx skills add https://github.com/mblode/agent-skills --skill multi-tenant-architectureIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill provides architectural guidance for building multi-tenant applications on Cloudflare and Vercel. It consists entirely of informational documentation and contains no executable code or scripts.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
- Runlayerwarn
6/7 files flagged
- ZeroLeakspass
Score: 93/100 · 2 sections analyzed
What does this agent skill do?
Multi-Tenant Platform Architecture (Cloudflare or Vercel)
- IS: domain strategy, tenant identification and isolation, subdomain routing, custom domains, white-label setup, and plan/limit mapping on Cloudflare or Vercel.
- IS NOT: general app folder structure or module boundaries (use
define-architecture), or scaffolding a new repo (usescaffold-nextjs).
Contents
- Platform dispatch (decide first)
- Workflow (order matters)
- Gotchas
- Output schema
- Pre-commit checklist
- Related skills
Platform dispatch (decide first)
| Signals | Platform | Load |
|---|---|---|
| Tenants run untrusted or per-tenant code; need code-level isolation; edge-first compute on D1/KV/Durable Objects | Cloudflare (Workers for Platforms, dispatch namespaces) | cloudflare-platform.md |
| All tenants share one Next.js codebase; need ISR, React Server Components, managed deploys | Vercel (App Router + Middleware) | vercel-platform.md, then vercel-domains.md for domains |
- Pick one platform and commit; never mix hosting (hybrid routing complexity compounds).
- Load only the chosen platform's references unless explicitly comparing.
- Load psl.md when deciding domain strategy (step 1).
- Load limits-and-quotas.md before mapping limits to pricing (step 8).
agents/openai.yamlis launcher metadata for external runners only; do not load it in normal use.
Workflow (order matters)
- Choose domain strategy
- Dedicated tenant domain, separate from the brand domain, for all subdomains and custom hostnames. Reputation does not isolate: a phishing site on
random.acme.comdamages the whole domain. - Register a separate TLD for tenant workloads (e.g.
acme.appfor tenants,acme.comfor brand). - Untrusted content on sibling subdomains: choose PSL submission, record owner plus timeline. Otherwise record
No PSLwith the cookie-isolation reason. See psl.md. - Start PSL early; review takes weeks.
- Choose tenant identification strategy (pick one primary; offer custom domain as upgrade path)
- Subdomain-based:
tenant.yourdomain.com. Requires wildcard DNS. Simplest at scale. - Custom domain: tenant CNAMEs their own domain to your platform. Best for serious/paying tenants.
- Path-based:
yourdomain.com/tenant-slug. No per-tenant DNS/SSL, but limits branding and complicates cookie isolation.
- Define isolation model
- Cloudflare: per-tenant Workers via dispatch namespaces for untrusted code. Avoid shared-tenant branching unless you fully control code and data.
- Vercel: shared Next.js app with
tenant_idscoping. Middleware resolves tenant from hostname; every query includes tenant context. Postgres RLS for defence-in-depth.
- Route traffic deterministically (tenants never control routing or see each other)
- Cloudflare: platform Worker owns routing: hostname -> tenant id -> dispatch namespace -> tenant Worker. 404 when no mapping.
- Vercel: Middleware extracts hostname, rewrites to a
/domains/[domain]segment; Edge Config for sub-millisecond lookups. 404 when no mapping.
- Pass tenant context through the stack (single authority: Middleware or platform Worker; never trust client-supplied identity)
- Cloudflare: platform Worker resolves the tenant, injects headers/bindings before dispatching to the tenant Worker.
- Vercel: Middleware sets
x-tenant-id,x-tenant-slug,x-tenant-planon forwarded request headers (not the response). Server Components read viaheaders(); API routes read from request headers:// middleware.ts import { NextRequest, NextResponse } from "next/server"; export function middleware(request: NextRequest) { const hostname = request.headers.get("host") ?? ""; const tenant = hostname.split(".")[0]; // resolve from Edge Config/DB in production const requestHeaders = new Headers(request.headers); requestHeaders.set("x-tenant-id", tenant); return NextResponse.next({ request: { headers: requestHeaders } }); }
- Bind only what is needed
- Cloudflare: least-privilege bindings per tenant (DB/storage/limited platform API), no shared global state. New bindings are explicit changes; redeploy to grant access.
- Vercel: Edge Config for tenant config (domain mappings, feature flags, plan info).
@vercel/sdkfor domain management. DB connections scoped bytenant_id, or database-per-tenant (Neon).
- Support custom domains and per-tenant static files
- Provide a DNS target, verify ownership, store the mapping, route by hostname.
- Cloudflare: Cloudflare for SaaS custom hostnames with managed certs. See cloudflare-platform.md.
- Vercel:
@vercel/sdkfor domain CRUD plus automatic Let's Encrypt SSL; wildcard subdomains require Vercel nameservers. See vercel-domains.md. - Custom domains shift reputation to the tenant and create natural user segments (casual on platform domain, serious on their own).
robots.txt,sitemap.xml,llms.txtmust vary by tenant; never serve from/public. Cloudflare: generate in the tenant Worker. Vercel: route handlers under the domain segment (see vercel-platform.md).
- Surface limits as plans
- Map platform limits to pricing tiers; expose in API and UI.
- No long jobs in requests; use queues or workflows.
- See limits-and-quotas.md; re-check official docs before final architecture or pricing decisions.
- Make the API the product
- Everything works over HTTP; the UI is for ops, incidents, billing.
- Platform logic stays in the routing layer (dispatch Worker or Middleware); tenant content serves requests.
- If it only works in the UI, the platform is leaking.
- Extend without breaking boundaries
- Add queues, workflows, or containers as optional modes. Keep routing explicit and isolation intact.
Gotchas
- Tenant headers go on the Middleware request, not the response:
headers()in Server Components reads forwarded request headers, so useNextResponse.next({ request: { headers } })or the tenant id never arrives. - Don't start path-based if custom domains are on the roadmap: migrating later means URL rewrites, cookie changes, and DNS migration.
- Never share DB connections across tenants without RLS or
tenant_idscoping: one missing WHERE clause leaks another tenant's data. - Never block
/.well-known/acme-challenge/*with Middleware or redirects: Let's Encrypt HTTP-01 validation fails and custom-domain SSL never issues. - Edge Config writes are not instant: propagation takes up to 10 seconds, so a "domain connected" UI reading Edge Config immediately shows stale state.
Output schema
# Multi-tenant architecture
## Platform decision
- Platform: Cloudflare | Vercel
- Why this platform:
- Rejected platform and reason:
## Domain map
- Brand domain:
- Tenant domain:
- Tenant subdomains:
- Custom domains:
- PSL decision: Submit | No PSL
- PSL owner/timeline or No PSL reason:
## Routing matrix
| Host pattern | Resolver | Destination | Unknown tenant behavior |
|---|---|---|---|
## Tenant context flow
- Authority: Middleware | platform Worker
- Propagation:
- Server read path:
- Database/API scoping:
## Isolation model
- Compute isolation:
- Data isolation:
- Config/binding isolation:
## Custom-domain lifecycle
1. DNS target:
2. Ownership verification:
3. Certificate provisioning:
4. Routing activation:
5. Removal/failure path:
## Limits-to-plan table
| Limit | Source URL/date | Free | Pro | Enterprise | Enforcement point |
|---|---|---:|---:|---:|---|
## Validation evidence
| Check | Command/source | Expected result | Result |
|---|---|---|---|
Pre-commit checklist
- Platform chosen with documented rationale
- Tenant workloads off the brand domain; PSL decision and timeline set
- Tenant identification strategy chosen; custom-domain upgrade path defined
- Isolation model defined: per-tenant Workers (Cloudflare) or shared-app plus RLS (Vercel)
- Routing authoritative and tenant-blind; dispatch or Middleware handles all traffic
- Tenant context flows through Middleware/platform Worker only; no client-supplied identity trusted
- Custom-domain onboarding defined: DNS target, verification, cert provisioning
- Per-tenant static files (robots.txt, sitemap.xml, llms.txt) served dynamically
- Limits tied to billing; API parity with UI
- Limits snapshot refreshed from official docs and dated in planning notes
Evidence commands (run or mark N/A):
| Check | Evidence |
|---|---|
| Tenant context exists at the boundary | `rg "x-tenant-id |
| Tenant routing works | curl -sI -H "Host: tenant.example.com" <local-or-preview-url> |
| Per-tenant static files are dynamic | curl -s -H "Host: tenant.example.com" <url>/robots.txt and curl -s -H "Host: tenant.example.com" <url>/sitemap.xml |
| Custom-domain verification path exists | API route, SDK call, or platform config path in the plan |
| Platform limits are up to date | official Cloudflare/Vercel URLs with access date in the Limits-to-plan table |
Related skills
define-architecture: folder structure, module contracts, and middleware pipelines for the application itself.scaffold-nextjs: bootstrap the Next.js turborepo before applying these tenancy patterns.optimise-seo: per-tenant sitemaps, canonical URLs, and structured data once routing works.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/mblode/agent-skills/multi-tenant-architecture">View multi-tenant-architecture on skillZs</a>