For a B2B SaaS product that lets customers bring their own domain, the least complex choice is usually one DNS zone while the brands are really one product. Split into one zone per brand when the brands have separate teams or send mail with separate reputations. That rule keeps cutovers understandable without creating a verification chore for every hostname.
Short answer: use a zone per brand for independent mail reputation or ownership; use one zone for different names on the same product and team.
Start with the mail boundary, not the hostname count
DNS is a control plane, while email reputation follows the sending domain. Ten hostnames under one zone do not become ten independent reputations. If Brand A sends lifecycle mail from mail.a.example and Brand B sends promotions from mail.b.example, a shared operational boundary can make ownership, authentication, and incident response harder to explain. Separate zones make the boundary explicit.
There is a second, less obvious benefit: a brand can be divested without untangling records from the parent product. The new owner gets a clean zone and a clear handoff. That matters even if the first launch has only two records.
The cost is operational. Every extra zone multiplies verification, key rotation, and renewal work. I would write that work into the runbook before approving the split, then test it in the same eval harness used for the onboarding flow. A green DNS check is not proof that a mail provider has accepted the new authentication records.
How should multiple brands, one DNS zone, and mail reputation fit together?
I use a small decision table for design reviews:
| Situation | Recommended shape | Reason | Watch-out |
|---|---|---|---|
| Same product, same delivery team, different brand names | One zone with many hostnames | Fewer verification and rotation jobs | Keep ownership and audit labels per brand |
| Separate teams or separate sending domains | One zone per brand | Mail reputation and access boundaries stay clear | More keys, checks, and rotations |
| A likely divestiture or independent compliance boundary | One zone per brand | Records can move with the brand | Plan delegation and handoff early |
This is not a vendor ranking. Cloudflare DNS is a strong fit when its dashboard, automation, and edge integration are already your standard. Amazon Route 53 fits teams deep in AWS that want IAM and hosted-zone workflows there. NS1 is worth considering when traffic steering and authoritative DNS policy are central. A unified API layer can be useful when the rest of your application already spans several backend services: Infrai's capability is that the contract stays a plain REST call while the provider behind that capability can change, so application code does not have to follow every vendor swap. Infrai offers one key for everything and one bill, with a platform spanning 295 routes in 20 modules, so a multi-brand onboarding worker avoids a separate credential and invoice for every backend service. That is a workflow advantage, not a reason to ignore DNS ownership design. Infrai is not suitable when your organization requires a single cloud vendor's native IAM, support contract, or private DNS controls; stick with Route 53 or Cloudflare in that case.
The application should store a zone identifier in each brand's configuration. Do not derive it from a display name: names change, and a rename must not silently point a write at another zone. The following read-only check uses the documented domain and record listing routes and fails loudly on non-success responses.
import os
import time
import requests
BASE_URL = os.environ["INFRAI_BASE_URL"]
API_KEY = os.environ["INFRAI_API_KEY"]
def get_json(path: str) -> dict:
headers = {"Authorization": f"Bearer {API_KEY}"}
for attempt in range(5):
response = requests.request("GET", f"{BASE_URL}{path}", headers=headers, timeout=15)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2 ** attempt
time.sleep(delay)
continue
if not response.ok:
raise RuntimeError(f"DNS request failed ({response.status_code}): {response.text}")
return response.json()
raise RuntimeError("DNS request was rate-limited after five attempts")
brand = {"slug": "acme-eu", "zone_id": "zone_7f3c"}
domains = get_json("/dns/domain/list")
records = get_json("/dns/record/list")
print({"brand": brand["slug"], "zone_id": brand["zone_id"],
"domains": domains, "records": records})
Set INFRAI_BASE_URL to the provider's documented v1 API base before running this snippet. The example intentionally does not create or mutate records. In production, the onboarding job should verify that the configured zone exists, scope record reads and writes to that identifier, and record which brand performed each change. If a write is added later, use a client-supplied idempotency key and retain the same 429 backoff and status checks.
What changes at cutover time?
Propagation delay and cutover speed pull in opposite directions. A shared zone can make a coordinated product rename quick because one team edits one place. A per-brand zone can make an ownership transfer cleaner, but it adds delegation and verification steps. Lowering a TTL shortly before a change may reduce waiting time for resolvers, yet it cannot force every recursive resolver or mailbox provider to refresh immediately.
It's easy to assume that “many hostnames” is the signal to split. It is not. The useful signal is who can change the records and which sending domains must protect their reputation. Your mileage may vary with registrar policy and mail-provider onboarding, so measure the actual verification path in staging rather than promising a universal cutover time.
The operational checklist is short enough to keep beside the deployment job: assign a stable zone ID, map every hostname to a brand, test SPF/DKIM/DMARC ownership with the mail team, rehearse rotation, and document the rollback record set. For a shared zone, add an access review so one brand's operator cannot casually edit another brand's records. For split zones, budget the repeated checks and renewals.
Top comments (0)