Why architecture matters here

The architecture matters because DNS is the one routing layer that sits in front of everything, before any connection is made, which makes it uniquely able to steer traffic across regions and away from whole failed sites. A load balancer can distribute traffic among the servers behind it, but it cannot help if the client cannot reach that load balancer's region at all; only DNS, which the client consults before connecting, can send the client to a different region's load balancer entirely. This is why cross-region failover and geographic steering live in DNS: it is the earliest point in the request lifecycle, the one place where you can change which datacenter the client heads toward. Nothing downstream can substitute for that.

The second forcing function is that DNS steering is coarse and eventually-consistent, and pretending otherwise causes outages. Because answers are cached for the TTL and beyond, DNS cannot make fine-grained, instantaneous routing decisions — it decides at resolution time, and that decision sticks in caches for a while. This means DNS is the right layer for decisions that change slowly and coarsely (which region, primary vs. backup, rough load split) and the wrong layer for decisions that must change instantly and per-request (which of these three healthy servers, right now). Teams that try to do per-request load balancing via DNS — tiny TTLs, rapidly changing answers — fight the caching layer, get inconsistent behavior, and still cannot achieve the granularity they want. Respecting DNS's coarse, cached nature is what makes it reliable; the fine work belongs downstream.

The third reason is that failover correctness hinges entirely on health checks and TTL, and both are easy to get wrong. Failover only works if the health checks accurately and quickly detect that an endpoint is bad and the DNS then stops returning it — but a health check that is too lax misses real failures (clients keep being sent to a dead endpoint), while one that is too aggressive flaps (marking a briefly-slow endpoint dead and shedding its traffic needlessly). And the TTL sets the floor on how fast a failover reaches clients: a one-hour TTL means clients can keep hitting a dead endpoint for up to an hour after you failed it over. Choosing a TTL is thus a direct trade between failover speed (short TTL, fast failover, but more DNS query load and less caching benefit) and efficiency (long TTL, cheap and cacheable, but slow failover). This single number is one of the most consequential settings in the whole architecture.

The fourth architectural payoff is that a handful of composable policies cover most real steering needs, so the design stays simple. Latency or geo routing sends each client to the nearest or fastest endpoint, cutting user latency and keeping traffic regional. Weighted routing splits traffic by proportion, which enables gradual rollouts and blue-green shifts by moving weight between endpoints. Active-passive failover sends everyone to a primary and switches to a standby only when health checks fail the primary. These compose — geo-route to the nearest region, and within the answer prefer the healthy endpoint, failing over to another region's endpoint if the local one is down — giving you locality in the normal case and survival in the failure case from the same DNS configuration. The power is in combining a few well-understood policies, not in inventing per-request cleverness DNS cannot deliver.

A fifth consideration is that much of the caching that governs failover speed is outside your control, and the architecture must be designed around that loss of control rather than assuming compliance. You set a TTL, but recursive resolvers at ISPs, corporate networks, and public DNS services may round it up, cap it, or serve stale answers under their own policies, and operating systems and browsers add their own caching layers on top. The practical consequence is that observed failover time is always longer than the TTL you configured, sometimes substantially, for a long tail of clients. This is why DNS failover is paired with, not relied upon exclusively for, high-availability: for fast failover you also need mechanisms that do not depend on clients re-resolving — anycast addressing, load-balancer-level health routing, or client retry logic — so that the slow, cache-bound DNS failover is a backstop rather than the sole line of defense. Designing for the caches you cannot control is what separates a robust failover story from one that works only in testing.

Advertisement

The architecture: every piece explained

Top row: the resolution path and the policy that shapes it. A client resolver asks for the app's name. The authoritative DNS — the server you control that owns the zone — does not just return a fixed record; it applies a routing policy to decide which address to hand back: geographic (nearest region), latency-based (fastest measured endpoint), or weighted (a proportional split). The policy chooses from the endpoint pool — the set of regional origins or load balancers that can serve the app — so different clients, or the same client at different times, may receive different addresses tailored to locality, load, or health.

Middle row: the health and caching machinery. Health checks continuously probe each endpoint from the DNS provider's vantage points, and the failover logic removes any endpoint that fails its checks from the set of answers, so new resolutions stop receiving a dead endpoint's address. The TTL on each answer tells resolvers how long they may cache it — the knob that trades failover speed against query load and caching efficiency. But the resolver / OS cache is the wildcard: recursive resolvers, operating systems, and browsers cache answers and may hold them past the TTL, so the address a client actually uses can lag what authoritative DNS is currently returning.

Bottom row: intent and its limits. Steering intent is what you are trying to express — send users to the nearest endpoint, split traffic by weight for a rollout, or keep an active-passive primary/standby pair — composed from the routing policies above. Propagation delay is the hard limit on how fast any change (a failover, a weight shift) actually reaches clients, bounded by the TTL and the misbehaving caches beyond it. The ops strip names the signals to watch: the health status of each endpoint, the measured failover time (how long until traffic actually moves), the configured TTLs, the distribution of queries across endpoints (is the steering doing what you intended?), and the stale-answer risk — the fraction of clients still using an old address after a change.

DNS failover & traffic steering — the DNS layer routes clients to healthy, nearby endpointshealth checks + routing policies decide which endpoint's address each resolver gets, and re-route on failureClient resolverasks for app.example.comAuthoritative DNSanswers per policyRouting policygeo / latency / weightedEndpoint poolregional origins / LBsHealth checksprobe each endpointFailover logicdrop unhealthy from answersTTLhow long clients cacheResolver / OS cachemay ignore your TTLSteering intentnearest, weighted, active-passivePropagation delayTTL + caching bound speedOps — health status + failover time + TTL + query distribution + stale-answer riskprobedropcacheobey?intentdelayresolveoperateoperate
DNS failover and traffic steering: a client resolver asks authoritative DNS for the app's address; a routing policy (geo, latency, or weighted) chooses which endpoint from the pool to answer with; health checks continuously probe each endpoint and failover logic removes unhealthy ones from answers; the TTL controls how long clients cache the answer — but resolver and OS caches may hold answers past the TTL, bounding how fast a failover actually reaches clients.
Advertisement

End-to-end flow

Follow a normal request under geo steering with failover. A user in Singapore resolves the app name; their query reaches the authoritative DNS, which applies a geographic routing policy, sees the client is in Asia, and returns the address of the ap-southeast endpoint — the nearest healthy one — with a sixty-second TTL. The client connects to ap-southeast at low latency and caches the answer for up to a minute. Simultaneously a user in Ireland resolves the same name and gets the eu-west endpoint's address instead. Each user was steered to their nearest region by the same DNS configuration returning different answers based on the resolver's location. Health checks are probing both endpoints continuously and both are healthy, so both stay in the answer set.

Now the ap-southeast endpoint fails — the region has an outage. The health checks probing it start failing; after enough consecutive failures to be confident (not so few that a transient blip trips it), the failover logic marks ap-southeast unhealthy and removes it from the answers. From that moment, new resolutions for Asian clients no longer receive ap-southeast; the policy falls back to the next-best healthy endpoint — say ap-northeast, or eu-west if that is next — and returns it instead. Asian users who resolve after the failover reach a working region. The application survived a regional outage with no client change, purely by the DNS ceasing to advertise the dead endpoint.

But watch the propagation reality that makes this gradual, not instant. The users who had already resolved ap-southeast in the sixty seconds before the failover still hold the dead address in their resolver and OS caches, and they keep trying to connect to it until their cache entry expires — up to the sixty-second TTL, and longer for resolvers that ignore it. During that window those users see errors or slow connections, mitigated only by client retry logic that re-resolves after a failure. This is why the TTL was set to sixty seconds rather than an hour: a shorter TTL shrinks this stale window, at the cost of more frequent DNS queries. The failover time the operator measures — how long until essentially all traffic has moved off ap-southeast — is the health-check detection time plus the TTL plus the tail of misbehaving caches.

Finally, use the same machinery for a controlled shift rather than a failure. To roll out a new version in eu-west, the operator uses weighted steering: initially ninety percent of eu-west traffic to the old endpoint and ten percent to the new, then, watching error and latency metrics, shifts the weights to fifty-fifty, then to the new endpoint entirely. Because the change is coarse and the TTL is short, each weight shift propagates within a minute, and a problem discovered at ten percent is contained to a tenth of traffic and reversed by shifting the weight back. The same DNS layer that fails over on a dead region also does gradual, health-observed rollouts — the routing policy is the dial, health checks are the safety, and the TTL sets how fast the dial turns. The operational cycle is: probe endpoints, steer per policy, remove the unhealthy, and accept that every change reaches clients only as fast as the caches allow.