Multi-Tenancy
ShipMore runs multi-tenant on a single box: one Next.js process, one MongoDB, one Stripe account, unlimited tenants. Each tenant is identified by its domain.
How tenancy resolves
Tenancy is host-based. The request host (e.g. mysite.com) maps to a tenant document in the tenants collection, and the rest of the request is served scoped to that tenant — its theme, site name, SEO defaults, and data. Admin (/admin), the Payload API (/api), and the /operate dashboard sit outside tenant resolution.
The practical upshot: you point any number of domains at one deployment, and each renders as its own isolated site.
Tenant scoping
Every operation is scoped to a single tenant, and access is governed by Payload’s role-based access control — one tenant’s data is never reachable from another’s.
Per-tenant search
Search is scoped per tenant: editorial content and dataset records are searched through separate, isolated indexes. See Data → Search & Explore.
Per-tenant branding & legal
Each tenant document holds:
- Site name + site logo
- Theme (one of the built-in themes — see Extras)
- Header / Footer / Banner layout configuration
- Legal pages (terms, privacy, license — Lexical rich text)
- Default SEO (title, description, OG image, favicon)
- Analytics (GA ID, custom scripts)
Local dev with multiple tenants
Use /etc/hosts to map aliases to 127.0.0.1, then create one tenant per alias. See Configure Tenants for the step-by-step.
Caveats:
- Use
.localor.testTLDs (Chrome force-redirects.devto HTTPS). - The tenant
domainmust include the port for local dev (e.g.tenant1.local:3000). - Cookies are domain-scoped — signing in on one tenant does not carry to another.
Production routing
- Railway — add each tenant domain as a Custom Domain on the same service; CNAME to Railway’s target.
- Vercel — every tenant domain must be added as a project Custom Domain; A/CNAME per Vercel’s instructions.
In both cases, traffic for any custom domain hits the same app, and the host-based rewrite resolves the tenant. See Deployment.