skip to content

What does cross-zone load balancing do in Elastic Load Balancing, and how does its default differ between an Application Load Balancer and a Network Load Balancer?

level: middleimportance: nice to knowfreq 40%

answer

  1. one node per enabled zone
  2. DNS splits by zone, not by target
  3. uneven target counts, uneven load
  4. on for ALB, off for NLB
  5. inter-AZ transfer is billed on NLB

basics

~20 s

Cross-zone load balancing lets each load balancer node send traffic to targets in every enabled Availability Zone, not just its own. It is on for an Application Load Balancer and off by default for a Network Load Balancer, where enabling it also incurs inter-AZ data transfer charges.

solid answer

~50 s

A load balancer has one node per enabled Availability Zone, and DNS hands clients one node address per zone, so incoming traffic arrives split roughly evenly across zones. With cross-zone load balancing **off**, each node only forwards to targets in its own zone, so unequal target counts per zone produce unequal load per target: two targets in one zone and eight in another means the two carry a quarter of the traffic each. With it **on**, every node spreads across all registered healthy targets. An Application Load Balancer has it enabled at the load balancer level, and since late 2023 you can turn it off per target group via `load_balancing.cross_zone.enabled`. A Network Load Balancer has it **off by default**, and turning it on means the traffic it sends across zones is billed as inter-AZ data transfer — an ALB's is not.

code

bash · 3 lines
bash
aws elbv2 modify-target-group-attributes \
  --target-group-arn "$TG_ARN" \
  --attributes Key=load_balancing.cross_zone.enabled,Value=false

go deeper

for a junior

Know the one-line definition: with cross-zone on, any load balancer node can send traffic to targets in any enabled Availability Zone; with it off, only to its own zone's targets.

for a middle

Work the arithmetic of uneven target counts out loud, and state the defaults correctly — enabled for an Application Load Balancer, disabled for a Network Load Balancer — plus the target-group attribute that overrides it.

for a senior

Bring in the consequences: inter-AZ data-transfer charges on NLB, per-zone healthy-host monitoring, and ensuring the Auto Scaling group balances targets across zones when cross-zone is off.

for a principal

Frame it as a blast-radius decision. Zonal isolation limits a zone-scoped failure to the clients resolved to that zone and enables zonal shift, at the price of stranded per-zone headroom and stricter capacity planning in every zone.

## The mechanism Enabling an Availability Zone on a load balancer creates a load balancer **node** in that zone with its own address. The load balancer's DNS name resolves to one address per enabled zone, and clients pick among them — with DNS round robin plus caching, that lands close to an even split **per zone**, not per target. Cross-zone load balancing decides what a node does next: - **Disabled** — a node forwards only to targets registered in its own zone. Traffic per zone is even; traffic per target is even only if every zone holds the same number of targets. - **Enabled** — every node forwards to every healthy target in every enabled zone. Traffic per target is even regardless of how targets are distributed. The classic illustration: 10 targets, 2 in `eu-west-1a` and 8 in `eu-west-1b`, with cross-zone off. Each zone's node receives about 50% of requests, so each `1a` target handles about 25% and each `1b` target about 6.25% — a fourfold imbalance created purely by placement. ## The defaults, per load balancer type - **Application Load Balancer** — cross-zone is on and cannot be disabled at the load balancer level. Since late 2023 it can be disabled **per target group** with the attribute `load_balancing.cross_zone.enabled`, whose values are `true`, `false` and `use_load_balancer_configuration`. - **Network Load Balancer** and **Gateway Load Balancer** — off by default; you enable it on the load balancer, and it can also be set per target group. ```bash aws elbv2 modify-target-group-attributes --target-group-arn "$TG_ARN" \ --attributes Key=load_balancing.cross_zone.enabled,Value=false ``` ## Cost, which is the part people miss For an ALB, traffic sent across Availability Zones by the load balancer is not charged as inter-AZ data transfer. For an NLB with cross-zone enabled, it is — regular inter-AZ data-transfer rates apply to the traffic the load balancer sends to targets in another zone. On a high-throughput NLB fronting a chatty internal service, that line item is easy to notice on the bill and easy to miss when planning. This asymmetry is the single most-quoted fact about the setting, and it is why NLB ships with cross-zone off. ## The availability argument Cost is not the only reason to leave it off. With cross-zone disabled, a request that entered through the `1a` node is served by a `1a` target: a failure confined to one zone — a bad deploy that only reached that zone's instances, a zonal dependency outage, a saturated zonal cache — stays confined to the clients that resolved to that zone's node. Cross-zone enabled means every node can send traffic into the sick zone, so a zonal problem becomes a fleet-wide error rate. This is the reasoning behind zonal-isolation architectures and behind zonal shift, which moves traffic away from an impaired zone by withdrawing that zone's load balancer node from DNS. The cost of that isolation is the imbalance above, plus reduced headroom: with cross-zone off, each zone must independently hold enough capacity to serve its share, so you cannot borrow idle capacity from a neighbour during a spike. ## Making the choice Keep it enabled when target counts per zone are uneven or change unpredictably, when the fleet is small enough that per-target imbalance matters, or when you value smooth utilisation over isolation. Turn it off when zonal blast-radius containment is an explicit goal, when the inter-AZ bill on an NLB is material, or when you have deliberately built independent per-zone stacks — and in that case make sure your Auto Scaling group or service scheduler actually balances targets evenly across zones, because without cross-zone that even placement is what keeps per-target load even. ## A related detail Disabling cross-zone also changes health semantics slightly: with it off, a zone whose targets are all unhealthy has no healthy target for its own node to use, and the clients that resolved to that node are affected specifically. Watch `HealthyHostCount` **per Availability Zone**, not just in aggregate — the aggregate looks fine right up until one zone empties.

  • Why does an even DNS split across zones not produce an even load per target?
    Because DNS distributes clients across load balancer nodes, one per zone, and each node's share is then divided among only the targets it can reach. With cross-zone off that is just its own zone's targets, so a zone with fewer targets gives each of them a larger slice of an equal zonal share.
  • With cross-zone disabled, which CloudWatch view matters most?
    HealthyHostCount and UnHealthyHostCount broken down by the Availability Zone dimension rather than aggregated. Aggregate counts stay comfortable while one zone drains to zero, and it is precisely that zone's clients — the ones whose DNS lookup returned its node — who see the failures.
  • Does disabling cross-zone load balancing give you any availability benefit?
    Yes, blast-radius containment: a request entering through one zone's node is served by that zone's targets, so a zone-scoped failure affects only clients resolved to that node instead of the whole fleet. That is the premise behind zonal isolation and behind zonal shift, which withdraws an impaired zone's node from DNS. The cost is uneven utilisation and no shared headroom.

saying these in an interview costs you the question

  • Believing DNS distributes traffic per target rather than per zone
  • Assuming cross-zone is off by default on an ALB
  • Thinking cross-zone traffic is free on every load balancer type
  • Claiming cross-zone can be disabled at the ALB level itself
  • Watching only aggregate healthy-host counts when cross-zone is off

context