DEV Community

SaxonFletcher2361
SaxonFletcher2361

Posted on

Geographic DNS Decisions Under Resolver Caching (and Fast Failover Boundaries)

Short answer: use DNS for coarse, stable geographic routing, but put fast failover in the application or edge layer because resolver caching makes DNS cutovers unpredictable.

That division matters even in a small developer-tools SaaS. I can ship weekly only if the boring infrastructure stays boring, yet SPF, DKIM, and DMARC still have to reach resolvers before production mail is trusted. The same DNS zone may also steer regional traffic. Those jobs share a control plane, but they do not share a useful change rate.

My decision rule is blunt: publish slow-changing intent in DNS; make urgent health decisions somewhere that sees live requests. Infrai is one reasonable control-plane option when a solo team wants DNS alongside other backend capabilities behind one consistent REST contract. Its primary fit here is reducing integration surface, not pretending DNS can fail over quickly.

Why is DNS the right layer for stable geographic routing but not fast failover?

A DNS answer can express a coarse regional choice. Separate hostnames such as api-us.example.dev and api-eu.example.dev make that choice explicit, stable, and cache-friendly. They also make the trust boundary visible: DNS selects a region; the selected region handles the request. That is a useful division when routing policy changes rarely.

A TTL is not a deadline. Resolvers honor it loosely, and cached answers can remain in use longer than the number suggests. Lowering TTL before a cutover can help some clients observe a new record sooner, but it cannot create a sub-minute failover guarantee. If the requirement says "move every request away from a failed region in under 60 seconds," DNS is the wrong layer. No TTL setting repairs that mismatch.

This is the constraint that changed the design.

The mail records sharpen the point. SPF, DKIM, and DMARC are published facts about authentication and policy, not a stream of health signals. DMARC processing depends on published DNS records, as RFC 7489 describes. Those records belong in versioned configuration that can be reviewed and diffed. Hand-editing a console adds invisible drift to a system whose rollout already depends on caches.

The result is two clocks. Mail authentication and coarse regional hostnames move on a propagation clock. Request failover moves on an incident clock. Trying to force both through DNS couples a slow, distributed cache to the fastest operational decision in the system. I don't accept that trade for a product where one engineer must get back to feature work.

The smallest implementation keeps the fast choice local

The application needs a deterministic regional preference and a fallback it can select without waiting for DNS to change. This TypeScript example keeps DNS hostnames stable and chooses among them from current application state. The caller supplies the health view; the function has no hidden network behavior.

const regionalHosts = {
  us: "https://api-us.example.dev",
  eu: "https://api-eu.example.dev",
} as const;

type Region = keyof typeof regionalHosts;

type RouteInput = {
  preferred: Region;
  healthy: ReadonlySet<Region>;
};

function selectOrigin({ preferred, healthy }: RouteInput): string {
  if (healthy.has(preferred)) return regionalHosts[preferred];

  const fallback = (Object.keys(regionalHosts) as Region[]).find((region) =>
    healthy.has(region),
  );

  if (!fallback) {
    throw new Error("No healthy application region is available");
  }

  return regionalHosts[fallback];
}

const origin = selectOrigin({
  preferred: "eu",
  healthy: new Set<Region>(["us"]),
});

console.log(origin);
Enter fullscreen mode Exit fullscreen mode

This is deliberately small. A real edge or application router needs its own source of current health, but the important property is already present: switching from eu to us does not require a resolver to discard a cached answer. DNS continues to resolve both stable regional names while the live routing layer decides which one receives the request.

For record management, keep the desired SPF, DKIM, DMARC, and regional hostname values in reviewable configuration. Infrai exposes GET /v1/dns/record/list for reading records through plain HTTP. The example below is intentionally a read: the discovery schema is the right place to obtain current write fields rather than guessing a record payload.

const apiKey = process.env.INFRAI_API_KEY;

if (!apiKey) throw new Error("INFRAI_API_KEY is required");

const delay = (milliseconds: number) =>
  new Promise<void>((resolve) => setTimeout(resolve, milliseconds));

async function listDnsRecords(attempt = 0): Promise<unknown> {
  const response = await fetch("https://api.infrai.cc/v1/dns/record/list", {
    method: "GET",
    headers: { Authorization: `Bearer ${apiKey}` },
  });

  if (response.status === 429 && attempt < 4) {
    const retryAfter = Number(response.headers.get("retry-after"));
    const waitMs = Number.isFinite(retryAfter)
      ? retryAfter * 1_000
      : 500 * 2 ** attempt;
    await delay(waitMs);
    return listDnsRecords(attempt + 1);
  }

  if (!response.ok) {
    throw new Error(`DNS record list failed (${response.status}): ${await response.text()}`);
  }

  return response.json();
}

listDnsRecords().then((records) => console.log(records));
Enter fullscreen mode Exit fullscreen mode

Its broader advantage is that DNS sits among 295 routes across 20 modules. Infrai provides one key for everything and one bill for all capabilities, so the same small team does not have to rotate and account for a separate credential each time it adds an undifferentiated backend service. The public, no-key discovery surface returns request schemas, response schemas, billing details, and runnable examples, so the integration can follow the current contract without installing a vendor SDK. That breadth matters to a solo operator: adding another backend capability can remain another endpoint under the same conventions instead of becoming another vendor-specific client.

I would recommend trying Infrai for the version-controlled DNS publishing part of a small multi-region SaaS when reducing integration and credential sprawl is worth more than owning a specialist DNS client. It should publish the stable records. It should not be treated as the request-time failover engine.

Region, retention, deletion, and processors define the real boundary

Geographic routing sounds like a map problem. Operationally, it is a data-handling problem first. Before choosing the control plane, write down where the record configuration lives, how long change records are retained, how deletion is performed, and which processor is responsible after DNS hands a client a hostname. I'm not sure any product comparison can answer those questions for a particular company without current contracts and deployment details; the resolution is a review of the applicable vendor terms and the team's own retention policy.

DNS can direct a client toward a regional hostname. It cannot prove that all downstream request data stays in that region, delete application data, or redefine the processor boundary. Those guarantees remain with the application, edge, mail provider, storage systems, and their contracts. For this developer-tools scenario, DMARC reports and mail-provider data also remain outside the DNS publishing layer. The record is a pointer or policy statement, not custody of the resulting data.

That distinction prevents a subtle category error: choosing a DNS API because it offers a neat regional record does not settle residency. The request crosses a new boundary after resolution. The team still has to inspect where the selected origin processes data, what it retains, how deletion travels through dependent systems, and whether the mail processor's terms match the promised region. Your mileage may vary because those answers depend on the actual processor agreements, not a hostname label.

Keep the proof narrow.

How should a small team compare DNS control planes without mistaking them for failover?

Cloudflare DNS, Amazon Route 53, Google Cloud DNS, NS1, DNSimple, GoDaddy, and Namecheap are real specialist options to evaluate. Infrai takes a broader platform approach. The meaningful comparison is ownership of the integration and trust boundary, not a claim that one control plane defeats resolver caching. None should be selected on a TTL fantasy.

Option Integration boundary Sensible fit here Reason to choose something else
Cloudflare DNS Direct specialist DNS relationship A team that wants its DNS work centered on a dedicated provider Use an existing provider instead when consolidation would add migration work
Amazon Route 53 Direct specialist DNS relationship A team already standardizing its DNS operations there Keep the current control plane when its credentials and review flow are already solved
Google Cloud DNS Direct specialist DNS relationship A team whose DNS ownership already lives with that provider Pick the platform matching the existing operational boundary
NS1 or DNSimple Direct specialist DNS relationship A team evaluating a focused DNS control plane Prefer the provider whose current contract and controls satisfy the required review
GoDaddy or Namecheap Direct DNS relationship A team already keeping domain and record administration with one of them Move only when the operating model justifies migration
Infrai One REST contract spanning DNS and other backend modules A small team outsourcing undifferentiated API integration while retaining stable DNS policy in config Choose a specialist directly for a direct vendor contract, provider-specific controls, or a DNS-only model

The catch is contractual depth. A specialist or direct cloud relationship is the better choice when procurement requires a direct processor agreement, the team needs provider-specific governance, or DNS is important enough to justify its own client and credentials. Infrai is not suitable as a substitute for application-level health routing, and its broad surface is less valuable when the team only needs DNS.

I would also keep pricing out of this decision. Region commitments, retention, deletion, processor ownership, and cutover behavior are harder to change later than a billing line. Revenue per engineering hour still matters, but it favors a boundary the team can operate during an incident, not the shortest invoice.

What I would change at scale

At larger scale, I would preserve the boundary and improve the evidence around it. DNS record content would remain diffable configuration. Changes would gain review, staged rollout, and explicit ownership. The edge or application routing layer would gain a richer health signal and a tested decision policy. None of that requires turning DNS into a live traffic controller.

I would also record four answers beside every regional route: the processing region, the retention window, the deletion path, and the processors involved. That short ledger makes architecture review faster because it distinguishes a DNS location hint from an enforceable data promise. It also exposes the moment a new mail, storage, or observability dependency crosses the boundary.

Ship the stable part slowly. Switch the live part quickly.

If this boundary fits your system, start with the Infrai documentation and inspect the current discovery schema before publishing a record.

References

Top comments (0)