Skip to content
AWS aws load-balancing 5 min read

Cross-Zone Load Balancing

An Elastic Load Balancer (ELB, the AWS service that spreads incoming traffic across many servers) does not run as a single machine. AWS places a separate load balancer “node” in each Availability Zone (AZ, an isolated data center inside an AWS Region) that you enable. Cross-zone load balancing controls whether each of those nodes is allowed to send traffic to targets in other AZs, or only to targets in its own AZ. This small switch has a big effect on how evenly your traffic spreads and, for some load balancer types, on your bill.

What cross-zone load balancing actually does

When a request reaches your load balancer, DNS (the Domain Name System, which turns names into IP addresses) hands the client one of the load balancer nodes — roughly one per AZ. That node then has to pick a backend server, called a target, to forward the request to.

  • Cross-zone ON: every node can send to any registered, healthy target across all enabled AZs. Traffic is spread evenly per target.
  • Cross-zone OFF: every node can only send to targets in its own AZ. Traffic is spread evenly per AZ first, then split among that AZ’s targets.

The difference matters most when your AZs hold uneven numbers of targets.

A worked example

Imagine 2 AZs receiving equal client traffic (50% each). AZ-A has 8 targets; AZ-B has 2 targets.

ModeHow a target in AZ-A is loadedHow a target in AZ-B is loaded
Cross-zone OFF50% / 8 = 6.25% each50% / 2 = 25% each
Cross-zone ON100% / 10 = 10% each100% / 10 = 10% each

With cross-zone off, the 2 targets in AZ-B each carry four times the load of a target in AZ-A — they can melt down while AZ-A sits idle. With cross-zone on, every target carries an identical 10%. That even distribution is the whole point.

Defaults differ by load balancer type

This is the gotcha most people miss: the default is not the same for every ELB type.

Load balancer typeCross-zone defaultWhere it’s configured
Application Load Balancer (ALB)ON (always; cannot be disabled at the LB level)Per target group
Network Load Balancer (NLB)OFFLB attribute or per target group
Gateway Load Balancer (GWLB)OFFLB attribute or per target group
Classic Load Balancer (CLB)OFF (API/CLI), ON (console)LB attribute

For an ALB (Layer 7, HTTP/HTTPS routing), cross-zone is on by default and inter-AZ traffic is free, so you almost never think about it. For an NLB (Layer 4, raw TCP/UDP at very high throughput), it is off by default — and turning it on can cost real money.

Cost gotcha: For an NLB, traffic that a node sends to a target in another AZ is billed as regular inter-AZ data transfer — roughly $0.01/GB out + $0.01/GB in = ~$0.02/GB in most Regions (2026 pricing; check your Region). On a high-throughput NLB pushing tens of TB, enabling cross-zone can add hundreds of dollars a month. ALB inter-AZ traffic is free, so this trade-off is unique to NLB/GWLB.

When to use this (and when not to)

Turn cross-zone ON when:

  • Your AZs have uneven target counts and you cannot guarantee balance (common with manual deployments or spot capacity).
  • Smooth, even per-target load matters more than a few dollars of data transfer (most ALB and web workloads).
  • You want resilience: if an AZ loses most of its targets, requests still flow to healthy targets elsewhere.

Leave cross-zone OFF when:

  • You run a high-throughput NLB where inter-AZ data transfer cost would be significant.
  • Your targets are evenly balanced across AZs (e.g. an Auto Scaling group that keeps equal capacity per AZ), so cross-zone adds cost with little benefit.
  • You need strict AZ isolation / locality — keeping traffic inside one AZ for latency or data-residency reasons.

How to change it — console

These steps assume an NLB or its target group, since that is where the setting is meaningful.

  1. Open the EC2 console and choose Target Groups (under Load Balancing) in the left menu.
  2. Select your target group, e.g. tg-nlb-app.
  3. Open the Attributes tab and choose Edit.
  4. Find Cross-zone load balancing. Choose On, Off, or Use load balancer setting.
  5. Choose Save changes.

To set it at the NLB level instead: Load Balancers -> select the NLB -> Attributes tab -> Edit -> toggle Cross-zone load balancing.

How to change it — AWS CLI

Enable cross-zone on a target group (works for NLB target groups):

aws elbv2 modify-target-group-attributes \
  --target-group-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/tg-nlb-app/0a1b2c3d4e5f6a7b \
  --attributes Key=load_balancing.cross_zone.enabled,Value=true

Output:

{
    "Attributes": [
        {
            "Key": "load_balancing.cross_zone.enabled",
            "Value": "true"
        }
    ]
}

Or set it once on the load balancer (the target group can inherit this):

aws elbv2 modify-load-balancer-attributes \
  --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/nlb-app/0a1b2c3d4e5f6a7b \
  --attributes Key=load_balancing.cross_zone.enabled,Value=true

Output:

{
    "Attributes": [
        {
            "Key": "load_balancing.cross_zone.enabled",
            "Value": "true"
        },
        {
            "Key": "deletion_protection.enabled",
            "Value": "false"
        }
    ]
}

Check the current value at any time:

aws elbv2 describe-target-group-attributes \
  --target-group-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/tg-nlb-app/0a1b2c3d4e5f6a7b \
  --query "Attributes[?Key=='load_balancing.cross_zone.enabled'].Value" \
  --output text

Output:

true

Infrastructure as Code

Terraform makes the per-target-group setting explicit:

resource "aws_lb_target_group" "nlb_app" {
  name        = "tg-nlb-app"
  port        = 443
  protocol    = "TCP"
  vpc_id      = "vpc-0a1b2c3d"
  target_type = "instance"

  # Off by default for NLB; turn on only if you accept the inter-AZ cost.
  load_balancing_cross_zone_enabled = true
}

CloudFormation uses the same attribute key:

NlbTargetGroup:
  Type: AWS::ElasticLoadBalancingV2::TargetGroup
  Properties:
    Name: tg-nlb-app
    Port: 443
    Protocol: TCP
    VpcId: vpc-0a1b2c3d
    TargetGroupAttributes:
      - Key: load_balancing.cross_zone.enabled
        Value: "true"

Best Practices

  • For ALB, leave cross-zone on (it is anyway) — inter-AZ traffic is free and even distribution is a pure win.
  • For NLB, start with the default (off) and only enable cross-zone if you see uneven per-target load you cannot fix by balancing capacity.
  • Keep target counts balanced across AZs with an Auto Scaling group; balanced capacity reduces the need for cross-zone in the first place.
  • Before enabling cross-zone on a high-volume NLB, estimate the inter-AZ data transfer cost (~$0.02/GB) against your monthly throughput.
  • Use the target-group-level setting (rather than the LB-level one) when different target groups behind the same NLB need different behavior.
  • Monitor the HealthyHostCount and per-target request/byte metrics in Amazon CloudWatch per AZ to confirm distribution matches your intent.
Last updated June 15, 2026
Was this helpful?