This guide explains how to set up TinaCMS to manage content for multiple tenants, each served under a unique domain, from a single codebase. It's ideal for projects where you want to centrally manage content and UI across brands or clients.
In a multi-tenant configuration:
The brain of multi-tenancy is the middleware, which inspects the domain of the request and dynamically rewrites the path to load the correct tenant content.
When a user visits tenant1.com, the middleware rewrites the request to /tenant1/... internally, allowing a single [tenant]/[slug]/page.tsx pattern to serve content for any domain.
We need the following
In your .env or Vercel environment variables, define the product-domain mapping:
NEXT_PUBLIC_PRODUCT_LIST = [{"product": "tenant1","domain": "tenant1.com"}, {"product": "tenant2","domain": "tenant2.ai"}]
Parse this list inside your middleware to map incoming domains to tenant IDs.
// middleware.tsimport { NextRequest, NextResponse } from 'next/server'const PRODUCT_LIST = JSON.parse(process.env.NEXT_PUBLIC_PRODUCT_LIST || '[]')const domainToProduct = Object.fromEntries(PRODUCT_LIST.map(({ domain, product }: any) => [domain, product]))export function middleware(request: NextRequest) {const hostname = request.headers.get('host') || ''const product = domainToProduct[hostname]if (product && !request.nextUrl.pathname.startsWith(`/${product}`)) {const url = request.nextUrl.clone()url.pathname = `/${product}${url.pathname}`return NextResponse.rewrite(url)}return NextResponse.next()}
Or find a more advanced middleware on the SSW Products Repository.
Structure your app/ folder like so:
|- app /| |- [tenant] /| |- [slug] /| |- page.tsx
Inside page.tsx, load content from the appropriate tenant folder:
const Page = async ({ params }: { params: { tenant: string; slug: string } }) => {const content = await getPageContent(`${params.tenant}/${params.slug}.mdx`)return <PageRenderer data={content} />}
Create tenant-specific folders in content/:
|- content /| |- docs /| |- tenant1 /| | |- intro.mdx| |- tenant2 /| |- intro.mdx
Ensure in TinaCloud that you add your respective site urls for each domain so that Tina can be used to manage your content!
For example, in Vercel:
If you want to clone down an example of a multi-tenant site, the SSW Products repository on GitHub implements multi-tenancy with TinaCMS.