Domain management for multi-tenant

Learn how to programmatically manage domains for your multi-tenant application using Vercel for Platforms.

If you plan on offering subdomains like *.acme.com, add a wildcard domain to your Vercel project. This requires using Vercel's nameservers so that Vercel can manage the DNS challenges necessary for generating wildcard SSL certificates.

  1. Point your domain to Vercel's nameservers (ns1.vercel-dns.com and ns2.vercel-dns.com).
  2. In your Vercel project settings, add the apex domain (e.g., acme.com).
  3. Add a wildcard domain: .acme.com.

Now, any tenant.acme.com you create—whether it's tenant1.acme.com or docs.tenant1.acme.com—automatically resolves to your Vercel deployment. Vercel issues individual certificates for each subdomain on the fly.

You can also give tenants the option to bring their own domain. In that case, you'll want your code to:

  1. Provision and assign the tenant's domain to your Vercel project.
  2. Verify the domain (to ensure the tenant truly owns it).
  3. Automatically generate an SSL certificate.

You can add a new domain through the Vercel SDK. For example:

import { VercelCore as Vercel } from '@vercel/sdk/core.js';
import { projectsAddProjectDomain } from '@vercel/sdk/funcs/projectsAddProjectDomain.js';
 
const vercel = new Vercel({
  bearerToken: process.env.VERCEL_TOKEN,
});
 
// The 'idOrName' is your project name in Vercel, for example: 'multi-tenant-app'
await projectsAddProjectDomain(vercel, {
  idOrName: 'my-multi-tenant-app',
  teamId: 'team_1234',
  requestBody: {
    // The tenant's custom domain
    name: 'customacmesite.com',
  },
});

Once the domain is added, Vercel attempts to issue an SSL certificate automatically.

If the domain is already in use on Vercel, the user needs to set a TXT record to prove ownership of it.

You can check the verification status and trigger manual verification:

import { VercelCore as Vercel } from '@vercel/sdk/core.js';
import { projectsGetProjectDomain } from '@vercel/sdk/funcs/projectsGetProjectDomain.js';
import { projectsVerifyProjectDomain } from '@vercel/sdk/funcs/projectsVerifyProjectDomain.js';
 
const vercel = new Vercel({
  bearerToken: process.env.VERCEL_TOKEN,
});
 
const domain = 'customacmesite.com';
 
const [domainResponse, verifyResponse] = await Promise.all([
  projectsGetProjectDomain(vercel, {
    idOrName: 'my-multi-tenant-app',
    teamId: 'team_1234',
    domain,
  }),
  projectsVerifyProjectDomain(vercel, {
    idOrName: 'my-multi-tenant-app',
    teamId: 'team_1234',
    domain,
  }),
]);
 
const { value: result } = verifyResponse;
 
if (!result?.verified) {
  console.log(`Domain verification required for ${domain}.`);
  // You can prompt the tenant to add a TXT record or switch nameservers.
}

Some tenants might want www.customacmesite.com to redirect automatically to their apex domain customacmesite.com, or the other way around.

  1. Add both customacmesite.com and www.customacmesite.com to your Vercel project.
  2. Configure a redirect for www.customacmesite.com to the apex domain by setting redirect: customacmesite.com through the API or your Vercel dashboard.

This ensures a consistent user experience and prevents issues with duplicate content.

If you offer both tenant.acme.com and customacmesite.com for the same tenant, you may want to redirect the subdomain to the custom domain (or vice versa) to avoid search engine duplicate content. Alternatively, set a canonical URL in your HTML <head> to indicate which domain is the "official" one.

If a tenant cancels or no longer needs their custom domain, you can remove it from your Vercel account using the SDK:

import { VercelCore as Vercel } from '@vercel/sdk/core.js';
import { projectsRemoveProjectDomain } from '@vercel/sdk/funcs/projectsRemoveProjectDomain.js';
import { domainsDeleteDomain } from '@vercel/sdk/funcs/domainsDeleteDomain.js';
 
const vercel = new Vercel({
  bearerToken: process.env.VERCEL_TOKEN,
});
 
await Promise.all([
  projectsRemoveProjectDomain(vercel, {
    idOrName: 'my-multi-tenant-app',
    teamId: 'team_1234',
    domain: 'customacmesite.com',
  }),
  domainsDeleteDomain(vercel, {
    domain: 'customacmesite.com',
  }),
]);

The first call disassociates the domain from your project, and the second removes it from your account entirely.

Here are a few common issues you might run into and how to solve them:

DNS propagation delays

After pointing your nameservers to Vercel or adding CNAME records, changes can take 24–48 hours to propagate. Use WhatsMyDNS to confirm updates worldwide.

Forgetting to verify domain ownership

If you add a tenant's domain but never verify it (e.g., by adding a TXT record or using Vercel nameservers), SSL certificates won't be issued. Always check the domain's status in your Vercel project or with the SDK.

Wildcard domain requires Vercel nameservers

If you try to add .acme.com without pointing to ns1.vercel-dns.com and ns2.vercel-dns.com, wildcard SSL won't work. Make sure the apex domain's nameservers are correctly set.

Exceeding subdomain length for preview URLs

Each DNS label has a 63-character limit. If you have a very long branch name plus a tenant subdomain, the fully generated preview URL might fail to resolve. Keep branch names concise.

Duplicate content SEO issues

If the same site is served from both subdomain and custom domain, consider using canonical tags or auto-redirecting to the primary domain.

Misspelled domain

A small typo can block domain verification or routing, so double-check your domain spelling.

Last updated on June 12, 2025