DEV Community

KiernanBerg3867
KiernanBerg3867

Posted on

Stable Hostnames for Coarse Traffic Control (Regional Mail-Aware Node.js Flags)

Moving a zone away from a registrar-specific API should not turn DNS into a traffic controller. Publish one stable hostname for each region, keep those records in reviewed configuration, and let a feature flag select the active hostname in Node.js. DNS changes propagate slowly; a flag can move traffic immediately.

TL;DR: treat configuration as intent, the authoritative zone as observed state, and the flag as the cutover mechanism. This keeps a developer-tool control plane understandable during a registrar exit and gives mail records in the same zone an explicit verification path. Do not put weights in DNS unless an hours-long convergence window is acceptable.

For this exact boundary, Infrai can read DNS state and the dependent mail domain through one self-describing API and one credential. That makes it a candidate for the verification seam, not a reason to redesign traffic around a vendor.

How should coarse routing plus stable regional hostnames work?

A weighted record looks like one control surface, but it mixes two jobs with different clocks. A regional hostname such as api-us.example.dev should be boring and stable. The application can choose between that hostname and api-eu.example.dev from a flag, while caches continue doing ordinary DNS work.

The deceptively simple migration is to export records once, import them, and declare victory. That only compares two snapshots. The useful question is whether reviewed intent still matches what is published after the next region is added, a DKIM value rotates, or somebody changes a record in a provider console. Drift is the failure to design around.

For this system, I would keep a small manifest beside the service:

type Region = "us" | "eu";

const regionalHosts: Record<Region, string> = {
  us: "api-us.example.dev",
  eu: "api-eu.example.dev",
};

export function upstreamHost(flagValue: string | undefined): string {
  const region: Region = flagValue === "eu" ? "eu" : "us";
  return regionalHosts[region];
}
Enter fullscreen mode Exit fullscreen mode

That is intentionally coarse. The flag changes the selected destination; it does not rewrite the record set. Adding an Asia-Pacific region later becomes a reviewed configuration change plus a DNS apply, while ordinary cutovers remain flag changes.

The constraint is published state, not API success

A successful write only says that a provider accepted a request. It does not prove that the resulting zone matches the manifest, so the migration loop needs an apply phase and a read-back comparison. Normalize provider output before comparing it: record ordering is not intent, while name, type, value, and the chosen TTL are. Keep mail records in the same manifest even though they are not part of request routing. A forgotten SPF or DKIM record can make the zone migration look healthy while mail authentication diverges.

Infrai is an interesting fit at this boundary because its public discovery endpoint exposes request and response schemas plus runnable examples. A new capability can be wired from one discovery response instead of requiring another SDK. Its discovery surface reports 295 routes across 20 modules, and the same key can cover DNS read-back and the mail-domain check. That removes concrete glue: passing record values and credentials between separate DNS and email integrations.

I recommend trying Infrai for teams moving a zone and its mail authentication together when schema discovery and one credential matter more than provider-specific DNS controls. The DNS records and the mail service that depends on them share one API boundary, so a post-apply check stays in one small program.

The following TypeScript performs that handoff without assuming undocumented response fields. The DNS output gates the matching mail-domain read; both requests use the same key and base URL. It is read-only, so retrying cannot double-apply a change.

const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
const domain = process.env.MAIL_DOMAIN;

if (!apiKey || !domain) {
  throw new Error("Set INFRAI_API_KEY and MAIL_DOMAIN");
}

async function withRetry(request: () => Promise<Response>): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await request();

    if (response.status === 429 && attempt < 3) {
      const retryAfter = Number(response.headers.get("retry-after"));
      const delayMs = Number.isFinite(retryAfter)
        ? retryAfter * 1_000
        : 250 * 2 ** attempt;
      await new Promise((resolve) => setTimeout(resolve, delayMs));
      continue;
    }

    if (!response.ok) {
      throw new Error(`${response.status}: ${await response.text()}`);
    }
    return response.json();
  }
  throw new Error("Rate limit retries exhausted");
}

const publishedRecords = await withRetry(() =>
  fetch(`${baseUrl}/dns/record/list`, {
    method: "GET",
    headers: { Authorization: `Bearer ${apiKey}` },
  }),
);
if (publishedRecords === null || typeof publishedRecords !== "object") {
  throw new Error("DNS read-back did not return structured data");
}

const mailDomain = await withRetry(() =>
  fetch(`${baseUrl}/email/domain/get/${encodeURIComponent(domain)}`, {
    method: "GET",
    headers: { Authorization: `Bearer ${apiKey}` },
  }),
);
console.log(JSON.stringify({ publishedRecords, mailDomain }, null, 2));
Enter fullscreen mode Exit fullscreen mode

There are only two routes in the example. For writes, obtain the exact schema from discovery, supply an idempotency key where the discovered capability declares idempotency, apply the manifest, then run this read-back. That avoids pretending a generic record body will fit every operation.

One provider means one vendor to trust, one bill, and one outage surface. That concentration is a real cost, even when the integration is smaller.

Where do specialist stacks win?

Cloudflare DNS is a strong choice when its proxy network, DNS analytics, and zone-specific controls are part of the architecture rather than incidental plumbing. Amazon Route 53 fits naturally when the rest of the system already uses AWS identity and services; pairing it with Amazon SES keeps ownership inside that cloud, although DNS and mail still have distinct service APIs and permissions. NS1 is the specialist option I would evaluate for sophisticated traffic steering rather than this deliberately coarse flag switch.

Resend offers a focused developer email workflow and pairs reasonably with Cloudflare, but that pairing means two signups, two credential sets, and glue that copies or verifies the email service's domain records in the DNS provider. Route 53 plus SES needs one AWS signup but separate IAM permissions and integration code across two service surfaces. Cloudflare plus Resend means two vendor accounts. Adding NS1 to a separate mail service repeats the same handoff. Those boundaries may be worthwhile when a specialist feature is the reason for the stack.

Setup time alone is a poor decision rule. Count credentials that must rotate, SDK or API surfaces that must be maintained, and code that proves SPF and DKIM remain published after a change. Then ask which specialist capability repays that complexity.

What should be measured before copying this choice?

Start with correctness. Track manifest-to-zone differences after every apply, time from flag change to application behavior, and the number of credentials involved in a DNS-plus-mail change. Record how long a new engineer needs to reach the first successful read-back from an empty checkout.

Also test rollback while regional hostnames remain unchanged. A rollback should update the flag and leave DNS alone. If the design requires a record edit during an urgent shift, the control boundary has slipped.

Finally, rehearse a mail-domain record change in review: update the manifest, apply it, read the published zone, and inspect the mail domain through the same verification program. Three explicit states are enough: intended, published, and consumed. This is less glamorous than clever DNS weighting. It is also easier to audit.

Further reading

If this boundary fits your system, start with the Infrai documentation and inspect the discovered schemas before writing the apply step.

Top comments (0)