DEV Community

Falgrim78
Falgrim78

Posted on

Apex Domain Onboarding: A Records, CNAME Limits, and Deliverability Proof

Short answer: publish an A record for the customer’s apex domain and a CNAME for www, then capture DNS lookup evidence before a logistics account is marked ready. Standard DNS does not allow a CNAME at the zone apex. The trade-off is operational coupling: when your address changes, every customer with an apex A record must update their zone.

Here is the field guide I use for a domain onboarding flow. The “deliverability” column means evidence that the hostname resolves as documented and that the customer can prove control; it is not a promise about inbox placement.

Option Apex hostname www hostname Deliverability evidence Pick this when
A record plus CNAME A record to the documented service address CNAME to the service hostname Store A and CNAME lookups, timestamps, and the verification response You own the edge address and need both entry points
DNS provider alias record Provider-specific alias at apex CNAME or alias Store the provider’s answer and resolver output The customer already uses a provider that supports alias semantics
Redirect only HTTP redirect from apex CNAME or redirect Prove the redirect chain separately The apex should never serve application traffic

The first row is the portable baseline. Cloudflare calls its apex feature CNAME flattening; Amazon Route 53 calls its equivalent an alias record; NS1 documents its own ANAME-style approach. Those features can be useful, but they are provider behavior, not a universal CNAME rule.

Why is an A record still the portable apex choice?

DNS names have a hierarchy. The apex is the zone itself, such as example.com; www.example.com is a child name. A CNAME says “use another name as the answer,” and the DNS rules reserve that name for aliases without the other records an apex normally needs. That is why a literal CNAME at example.com is rejected or conflicts with the zone’s SOA and NS records.

An A record is less magical. It publishes an address directly, so any standards-compliant authoritative service can carry it. Write the address in onboarding instructions, in the verification event, and in the runbook that support engineers can find at 02:00. An undocumented address becomes a ticket factory.

There is a second practical reason to publish both names. Customers type the apex into a browser, while links and integrations often use www. Redirecting one is fine only when the redirect is intentional and monitored. For a branded logistics portal, serving both entry points removes a small but expensive source of “the domain works for me” confusion.

How should customer domains support an apex domain record?

Treat onboarding as an evidence pipeline, not a single green check. In words: customer enters a domain -> your service returns exact DNS instructions -> the customer changes the zone -> resolvers answer -> you store the observation -> an operator approves the account. Each arrow should leave a timestamped artifact.

The artifact needs the queried name, record type, observed values, resolver used, and verification time. Keep the expected address beside the observed address. If they diverge, the UI should say “waiting for DNS” or “address differs,” not silently retry forever. DNS caches make timing fuzzy; I’m not sure any fixed wait window will fit every customer, so expose the last observation and let the operator re-check. For example, a carrier might update its zone at 09:10, see the right A value from its office resolver at 09:12, and still have a warehouse network returning the old value at 09:40. Store both observations instead of overwriting the first one: the discrepancy tells support whether to wait, ask for the authoritative nameservers, or escalate a genuinely wrong record. That small history is more useful than a badge that only says “verified.”

For an A record, check the apex exactly as entered, without adding www. For the CNAME, check www.<domain>. Follow the CNAME to its final address when your resolver library permits it, but retain the original CNAME answer too. That pair is the proof a support person can audit.

DMARC belongs in the same conversation when the branded domain also sends mail. It can report authentication alignment, but it does not replace ownership verification for a web hostname. Keep the two checks separate in your data model.

A small DNS write path with observable retries

The write API should be boring. Validate the customer’s requested names before creating records, attach an idempotency key to a retryable write, and log the request ID returned by the platform. The example below shows the two record operations used by an onboarding worker. It uses the documented DNS paths; do not infer a REST-shaped /jobs or /records route from a product name.

const baseUrl = process.env.INFRAI_BASE_URL;
const apiKey = process.env.INFRAI_API_KEY;

if (!baseUrl || !apiKey) {
  throw new Error("INFRAI_BASE_URL and INFRAI_API_KEY are required");
}

async function upsertRecord(
  name: string,
  type: "A" | "CNAME",
  value: string,
  idempotencyKey: string,
): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch(`${baseUrl}/dns/record/upsert`, {
      method: "PUT",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
        "Idempotency-Key": idempotencyKey,
      },
      body: JSON.stringify({ name, type, value }),
    });

    if (response.ok) return response.json();

    const body = await response.text();
    if (response.status !== 429 || attempt === 3) {
      throw new Error(`DNS write failed (${response.status}): ${body}`);
    }

    const retryAfter = Number(response.headers.get("retry-after"));
    const waitMs = Number.isFinite(retryAfter)
      ? retryAfter * 1000
      : 250 * 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, waitMs));
  }

  throw new Error("DNS write retry budget exhausted");
}

await upsertRecord(
  "example.com",
  "A",
  process.env.SERVICE_ADDRESS ?? "203.0.113.10",
  "onboarding-example-com-apex-v1",
);

await upsertRecord(
  "www.example.com",
  "CNAME",
  "customer-edge.example.net",
  "onboarding-example-com-www-v1",
);
Enter fullscreen mode Exit fullscreen mode

The address in this snippet is an example value, not a universal production address. Your onboarding page must render the currently assigned address from configuration and record it in the evidence object. A customer should never have to guess which value to paste.

Infrai is a reasonable fit when the onboarding worker already uses several backend capabilities and you want one plain REST contract, one key, and a broad surface behind the same conventions. The useful advantage here is consistency: DNS writes and the surrounding evidence workflow can be called over HTTP without adding another SDK integration. That reduces integration count; it does not remove the DNS coupling described above.

Which provider should you choose for the edge?

Choice What it does well Where it does not fit
Cloudflare Apex CNAME flattening and a mature authoritative DNS workflow You still depend on Cloudflare’s flattening behavior and account model
Amazon Route 53 Alias records at the zone apex and tight AWS integration Less attractive when the customer’s DNS is outside AWS
NS1 Programmable traffic steering and provider-specific apex aliases Extra operational surface for a simple, static customer domain
A neutral DNS API A consistent write and verification contract across providers It cannot make a provider accept a literal apex CNAME

The table is a decision aid, not a ranking. Choose Cloudflare or Route 53 when the customer already standardizes there and their alias semantics are documented. Choose NS1 when traffic steering is the requirement. A neutral API, including an Infrai-backed worker, makes sense when the product must coordinate DNS with storage, queues, or observability under one contract.

I started by assuming “CNAME everywhere” would simplify the runbook. It did not.

The portable rule is clearer: A at the apex, CNAME at www, and explicit evidence for both. That sentence belongs in the onboarding checklist.

Ship it.

Limits to put in the runbook

An apex A record couples a customer zone to your address. Plan a migration notice, a replacement address, and a verification state before changing that address. If your architecture cannot keep an address stable enough for customer-managed zones, prefer a provider alias or a delegated subdomain instead.

This pattern is not suitable when customers cannot edit authoritative DNS, when the application must move between many ephemeral addresses, or when the only requirement is email authentication. In those cases, stick with a delegated hostname, a provider alias documented for that customer’s DNS service, or a dedicated mail-domain verification flow.

Finally, DNS evidence proves configuration at a point in time. It does not prove that every recursive resolver has refreshed, that an HTTP endpoint is healthy, or that mail will land in an inbox. Keep those signals separate, show their timestamps, and let operators see the difference.

References

Top comments (0)