Last updated:
Short answer: Use an Application Load Balancer (ALB) for HTTP, HTTPS and gRPC when you need routing by host, path or header, AWS WAF, user authentication or Lambda targets. Use a Network Load Balancer (NLB) for TCP, UDP, TLS or QUIC traffic, static IP addresses, AWS PrivateLink, or TLS that must stay encrypted all the way to your targets.
ALB vs NLB at a glance
| Application Load Balancer (ALB) | Network Load Balancer (NLB) | |
|---|---|---|
| OSI layer | Layer 7 (application) | Layer 4 (transport) |
| Listener protocols | HTTP, HTTPS (HTTP/2 and gRPC over HTTPS) | TCP, UDP, TCP_UDP, TLS, QUIC, TCP_QUIC |
| Routing | Listener rules on host, path, HTTP headers, method, query string and source IP; redirects, fixed responses, weighted target groups | Flow hash per connection; weighted target groups; on dual-stack NLBs, rules by source IP version (IPv4 or IPv6) only |
| Static IP / Elastic IP | No; use the DNS name (or put an NLB or AWS Global Accelerator in front) | Yes: one static IP per enabled AZ, optional Elastic IP per subnet (internet-facing) |
| Client IP at the target | Load balancer’s IP on the packet; client IP in X-Forwarded-For |
Preserved for instance targets and for UDP/QUIC; off by default for ip targets on TCP/TLS (turn it on, or use proxy protocol v2) |
| Security groups | Always used | Optional, and only if attached at creation |
| Target types | Instance, IP, Lambda | Instance, IP, ALB |
| WebSockets | Yes (HTTP/1.1 upgrade on HTTP and HTTPS listeners) | Yes on TCP, TLS, TCP_UDP and TCP_QUIC listeners |
| TLS termination | HTTPS listener; mutual TLS (verify or passthrough) | TLS listener with optional ALPN; or TCP passthrough on 443; no mutual TLS at the load balancer |
| Health checks | HTTP or HTTPS (gRPC status codes for gRPC targets) | TCP (default), HTTP or HTTPS |
| Cross-zone default | Always on at load balancer level; can be turned off per target group | Off by default; turn on per load balancer or target group |
| Idle timeout | 60 seconds by default (configurable) | TCP: 350 seconds by default, configurable from 60 to 6,000 |
| IPv6 | IPv4, dual-stack, dual-stack without public IPv4 | IPv4, dual-stack |
| Minimum zones | Two Availability Zones | One Availability Zone (more recommended) |
| Typical uses | Websites, REST and gRPC APIs, microservices, containers, Lambda back ends | Non-HTTP TCP/UDP services, gaming, IoT, PrivateLink services, fixed-IP allowlists, end-to-end TLS |
| Pricing model | Hourly charge plus Load Balancer Capacity Units (LCUs) | Hourly charge plus Network Load Balancer Capacity Units (NLCUs) |
Features from AWS documentation, checked October 16, 2026. AWS adds load balancer features often, so confirm in the linked docs before you design around one.
What is an Application Load Balancer?
An Application Load Balancer works at the application layer, the seventh layer of the OSI model. It terminates the client’s connection, reads each HTTP request and evaluates your listener rules in priority order. Each rule has conditions (host header, path, HTTP header, method, query string or source IP) and an action: forward to a target group, redirect, or return a fixed response.
That makes ALB the natural front door for web applications and microservices. One ALB can serve api.example.com and www.example.com, send /images/* to one service and /api/* to another, and redirect HTTP to HTTPS.
Facts worth remembering:
- Listeners: HTTP and HTTPS on ports 1 to 65535. HTTP/2 from clients works on HTTPS listeners, with up to 128 parallel requests per connection.
- gRPC: set the target group’s protocol version to gRPC. This needs an HTTPS listener and
instanceoriptargets, and the health check uses a method path such as/package.service/method. - Targets: EC2 instances, IP addresses (including on-premises over Direct Connect or VPN, from private ranges) and AWS Lambda functions. ALB is the only load balancer type that supports Lambda targets.
- Extras at layer 7: AWS WAF integration, user authentication through corporate or social identity providers, sticky sessions with cookies, slow start, and routing algorithms (round robin by default, least outstanding requests, or weighted random).
- Zones: you must enable at least two Availability Zones.
What is a Network Load Balancer?
A Network Load Balancer works at the fourth layer of the OSI model and is designed to handle millions of requests per second. It doesn’t read HTTP. For TCP, it picks a target with a flow hash of the protocol, source and destination IP and port, and the TCP sequence number, then keeps that connection on the same target for its lifetime. UDP flows are hashed the same way without the sequence number.
Facts worth remembering:
- Listeners: TCP, TLS, UDP, TCP_UDP, QUIC and TCP_QUIC on ports 1 to 65535. QUIC support arrived in November 2025 in passthrough mode: NLB routes QUIC by the server ID in the connection ID, supports QUIC v1 only, and doesn’t allow QUIC listeners on dual-stack NLBs or NLBs with security groups.
- Static IPs: each enabled Availability Zone gets a network interface with a static IP. For an internet-facing NLB you can attach one Elastic IP per subnet, which is what partners with firewall allowlists usually want.
- Targets: EC2 instances, IP addresses (private ranges), or one Application Load Balancer per target group. No Lambda targets.
- PrivateLink: NLB is the load balancer you put behind a VPC endpoint service when you share a TCP or TLS service privately with other VPCs and accounts.
- Listener rules (new in July 2026): dual-stack NLBs can route by the client’s IP version, sending IPv4 clients to IPv4 targets and IPv6 clients to IPv6 targets. It is not content-based routing.
How do ALB and NLB differ in practice?
Which OSI layer does each one work at, and why does it matter?
Layer 7 means the ALB sees URLs, headers and cookies, so it can make a decision per request. Layer 4 means the NLB sees IP addresses, ports and connections, so it makes a decision per connection or flow. If your rule needs the word “path”, “host” or “header”, you need an ALB. If your protocol isn’t HTTP, or you need the load balancer to stay out of the payload, you need an NLB.
Does the load balancer get a static IP address?
NLB does: one per enabled zone, optionally an Elastic IP you own. ALB does not offer static or Elastic IPs, and clients should always resolve its DNS name, because the addresses behind it change as it scales. If a partner insists on fixed IPs for an HTTP application, you have two documented options: register the ALB as a target of an NLB, or put AWS Global Accelerator in front, which provides two static anycast IPv4 addresses.
Will my application see the client’s IP address?
With an ALB, the TCP connection to your target comes from the load balancer, so server logs show the ALB’s private IP. The client address is in the X-Forwarded-For header, which ALB appends by default (you can set it to preserve or remove instead). Only trust that header when it was added by systems you control.
With an NLB, it depends on the target group:
instancetargets: the client IP is preserved on the packet by default.iptargets with TCP or TLS: preservation is off by default. Turn onpreserve_client_ip.enabled(target in the same or a peered VPC), or turn on proxy protocol v2 and read the client address from the header.- UDP, TCP_UDP, QUIC and TCP_QUIC: preservation is always on and can’t be turned off.
Preserved client IPs change your security group design. Your targets now see client addresses, not the NLB’s, so the target security group must allow them. The cleanest fix is to give the NLB a security group and reference it in the target’s rules.
How do security groups work with ALB and NLB?
An ALB always has security groups. Their rules must allow traffic in both directions on the listener ports and the health check ports, so review them whenever you add a listener or change a health check port.
NLB support for security groups is newer, and it comes with one trap: you can only associate security groups when you create the NLB. If you create it without any, you can’t add them later; you would have to replace the load balancer. Once an NLB has security groups, you can change them at any time. Health checks are subject to the NLB’s outbound rules, and AWS doesn’t charge for traffic that the inbound rules block. The trade-off: QUIC and TCP_QUIC listeners aren’t allowed on an NLB that has security groups.
Where should TLS be terminated?
You have three patterns:
- Terminate on the ALB (HTTPS listener). The ALB decrypts, applies rules and WAF, and can re-encrypt to HTTPS targets. ALB also supports mutual TLS: in verify mode it checks client certificates against a trust store you upload; in passthrough mode it forwards the client certificate chain to your targets in HTTP headers.
- Terminate on the NLB (TLS listener). Good for non-HTTP protocols over TLS, or HTTP when you don’t need layer 7 features. You can set an ALPN policy such as
HTTP2Preferred; the default isNone. NLB does not support mutual TLS at the load balancer. - Pass through (NLB TCP listener on 443). The NLB forwards encrypted bytes untouched and your targets hold the certificates. Use this when compliance says keys live only on your servers, or when targets must do mutual TLS themselves.
One practical detail: for both ALB and NLB, the console’s default security policy is ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09, but the AWS CLI, CloudFormation and the CDK default to the much older ELBSecurityPolicy-2016-08. Set --ssl-policy explicitly in scripts and templates.
How do cross-zone defaults differ?
With cross-zone load balancing on, each load balancer node spreads traffic across targets in all enabled zones. With it off, each node only uses targets in its own zone. ALB has it on at the load balancer level and lets you turn it off per target group. NLB has it off by default.
That default matters when your zones are uneven. With two zones, two targets in one and eight in the other, and cross-zone off, each of the two targets gets 25% of the traffic while each of the eight gets 6.25%. Turning cross-zone on evens it out to 10% each. On NLB, turning it on also means you pay regional data transfer for traffic that crosses zones, so the alternative is to keep it off and balance target counts per zone.
What about idle timeouts and long-lived connections?
ALB closes a connection that has been idle for 60 seconds by default (idle_timeout.timeout_seconds), and has a separate client keepalive duration of 3,600 seconds. If you run long requests or quiet WebSocket connections, raise the idle timeout or send keepalives.
NLB’s TCP idle timeout defaults to 350 seconds and is configurable per listener from 60 to 6,000 seconds (tcp.idle_timeout.seconds). Database connection pools and IoT clients that sit quiet for minutes are the classic reason to change it.
Both handle WebSockets. On ALB, once a connection upgrades to WebSocket, listener rules and AWS WAF no longer apply to it. On NLB, WebSockets work on TCP, TLS, TCP_UDP and TCP_QUIC listeners.
How do health checks differ?
ALB health checks are HTTP or HTTPS GET requests to a path you choose (default /), and a target is healthy when it returns a code you allow (200 by default, configurable from 200 to 499). For gRPC target groups you match gRPC status codes instead.
NLB defaults to a simple TCP health check and also supports HTTP and HTTPS. NLB health checks are distributed and use a consensus mechanism, so each target receives more checks than the interval suggests. Keep the HTTP health check endpoint cheap, such as a static page. If health checks fail and you can’t see why, test the port from inside the VPC with curl and ss; the Linux networking basics module walks through both.
How is each one priced?
This post doesn’t quote prices; they vary by Region and change. What matters for design is the model:
- ALB: an hourly charge plus LCUs. An LCU is measured on four dimensions: new connections, active connections, processed bytes and rule evaluations. You pay for whichever dimension is highest each hour. More than 10 rules per request adds to the rule-evaluation dimension, and mutual TLS lowers the active connections that one LCU covers.
- NLB: an hourly charge plus NLCUs, measured on new connections or flows, active connections or flows, and processed bytes, again billed on the highest. TCP, UDP and TLS traffic are counted separately, and a TLS listener uses capacity much faster per new connection than plain TCP (an NLCU covers 800 new TCP connections per second but only 50 new TLS connections).
- Both: standard data transfer charges, and charges for every public IPv4 address the load balancer uses.
Check Elastic Load Balancing pricing and model your traffic in the AWS Pricing Calculator.
Which one should you use? A decision guide
| Your situation | Pick | Why |
|---|---|---|
| Website or REST API with paths, hosts or subdomains | ALB | Listener rules route per request |
| gRPC services | ALB | gRPC protocol version on an HTTPS listener |
| HTTP API on AWS Lambda | ALB | Only ALB supports Lambda targets |
| Clients authenticate with certificates at the load balancer | ALB with mutual TLS | NLB has no mTLS at the load balancer |
| Game servers, VoIP, DNS or other UDP | NLB | ALB has no UDP listeners |
| HTTP/3 over QUIC handled by your own servers | NLB (QUIC or TCP_QUIC) | QUIC passthrough; no security groups on that NLB |
| Partner needs fixed IPs to allowlist | NLB with Elastic IPs | Static IP per zone |
| Fixed IPs and path or host routing | NLB in front of ALB | NLB gives the IPs, ALB the rules |
| Share a TCP service privately with other VPCs or accounts | NLB behind a VPC endpoint service | PrivateLink endpoint services use NLB |
| TLS must be decrypted only on your servers | NLB, TCP listener on 443 | Encrypted traffic passes through |
| Firewall or IDS appliances inspecting all traffic | Gateway Load Balancer | Layer 3, GENEVE to appliances |
To make the first questions concrete, here is a small Python rule-of-thumb picker. It is a teaching aid, not a sizing tool.
"""Rule-of-thumb picker: Application Load Balancer or Network Load Balancer?
It encodes the first questions an architect asks about a workload. It is a
teaching aid, not a sizing tool: confirm features and quotas in the AWS docs.
Run: python3 pick_load_balancer.py
"""
def pick_load_balancer(protocol: str, *, static_ip: bool = False,
privatelink: bool = False, l7_routing: bool = False,
lambda_target: bool = False, client_cert_auth: bool = False,
targets_decrypt_tls: bool = False,
inline_appliance: bool = False) -> str:
"""Return a recommendation with a one-line reason.
protocol -- "http", "https", "grpc", "websocket", "tcp", "tls",
"udp" or "quic"
static_ip -- clients or partners must allowlist fixed IPs
privatelink -- expose the service to other VPCs as an endpoint service
l7_routing -- route by host, path, header, method or query string
lambda_target -- send requests to an AWS Lambda function
client_cert_auth -- the load balancer itself must verify client certificates
targets_decrypt_tls -- TLS must stay end to end, decrypted only on the targets
inline_appliance -- inspect all traffic with firewall/IDS appliances
"""
if inline_appliance:
return "Gateway Load Balancer: layer 3 gateway for GENEVE appliances"
if protocol in ("udp", "quic"):
return "NLB: UDP and QUIC listeners (ALB listens on HTTP/HTTPS only)"
if targets_decrypt_tls:
return "NLB with a TCP listener on 443: encrypted bytes pass through untouched"
web = protocol in ("http", "https", "grpc", "websocket")
if web and (static_ip or privatelink):
if l7_routing or lambda_target or client_cert_auth:
return ("NLB in front of ALB (target type alb): static IPs or "
"PrivateLink from NLB, HTTP routing from ALB")
return "NLB: static IP per AZ and PrivateLink; HTTP stays opaque to it"
if lambda_target:
return "ALB: the only load balancer with Lambda targets"
if client_cert_auth:
return "ALB with mutual TLS (verify mode): NLB does not support mTLS"
if protocol == "grpc":
return "ALB: HTTPS listener plus gRPC protocol version on the target group"
if web:
return "ALB: layer 7 rules, redirects, WAF and X-Forwarded-For"
if protocol in ("tcp", "tls"):
if privatelink:
return "NLB: a PrivateLink endpoint service is fronted by an NLB"
return "NLB: layer 4 TCP/TLS with flow hash routing"
raise ValueError(f"unknown protocol: {protocol}")
scenarios = [
("Public website: /api to containers, /images to another service",
dict(protocol="https", l7_routing=True)),
("gRPC microservices behind one HTTPS endpoint", dict(protocol="grpc")),
("Multiplayer game server on UDP 7777", dict(protocol="udp")),
("Partner must allowlist fixed IPs; API uses host-based routing",
dict(protocol="https", static_ip=True, l7_routing=True)),
("SaaS database proxy shared with customer VPCs over PrivateLink",
dict(protocol="tcp", privatelink=True)),
("Payments service: TLS must be decrypted only on the targets",
dict(protocol="tls", targets_decrypt_tls=True)),
("Serverless HTTP API on Lambda", dict(protocol="https", lambda_target=True)),
("IoT devices authenticate with client certificates over HTTPS",
dict(protocol="https", client_cert_auth=True)),
("Inline firewall fleet for all VPC egress", dict(protocol="tcp", inline_appliance=True)),
]
for name, kwargs in scenarios:
print(f"{name}\n -> {pick_load_balancer(**kwargs)}")
Output (Python 3.13.5, run on October 16, 2026):
Public website: /api to containers, /images to another service
-> ALB: layer 7 rules, redirects, WAF and X-Forwarded-For
gRPC microservices behind one HTTPS endpoint
-> ALB: HTTPS listener plus gRPC protocol version on the target group
Multiplayer game server on UDP 7777
-> NLB: UDP and QUIC listeners (ALB listens on HTTP/HTTPS only)
Partner must allowlist fixed IPs; API uses host-based routing
-> NLB in front of ALB (target type alb): static IPs or PrivateLink from NLB, HTTP routing from ALB
SaaS database proxy shared with customer VPCs over PrivateLink
-> NLB: a PrivateLink endpoint service is fronted by an NLB
Payments service: TLS must be decrypted only on the targets
-> NLB with a TCP listener on 443: encrypted bytes pass through untouched
Serverless HTTP API on Lambda
-> ALB: the only load balancer with Lambda targets
IoT devices authenticate with client certificates over HTTPS
-> ALB with mutual TLS (verify mode): NLB does not support mTLS
Inline firewall fleet for all VPC egress
-> Gateway Load Balancer: layer 3 gateway for GENEVE appliances
Notice the order of the checks. Appliance and protocol questions come first, because they rule one option out entirely. Fixed IPs and PrivateLink come next, because they force an NLB even for HTTP traffic. Only then do the layer 7 features decide between NLB alone and NLB in front of ALB.
Choosing a load balancer is a common theme in AWS Solutions Architect Associate exam scenarios. Watch for the clue words: “static IP”, “UDP”, “path-based”, “PrivateLink”, “client certificate”, “Lambda”. The AWS Solutions Architect course practices these scenarios in labs.
Can you put an NLB in front of an ALB?
Yes, and it is the standard answer when you need both worlds. You create a target group of type alb with protocol TCP, register the ALB, and point an NLB TCP listener at it. The NLB provides static IPs and PrivateLink; the ALB keeps its layer 7 rules, WAF and certificates.
Know the constraints before you design around it:
- Both load balancers must be in the same VPC and the same account.
- One ALB per target group, and one ALB can be a target of up to two NLBs.
- Only TCP listeners on the NLB can forward to an ALB target group, and the target group port must match an ALB listener port.
- Health checks to the ALB must be HTTP or HTTPS.
- Target group attributes for type
albare fixed at their defaults, and traffic between the NLB and the ALB always uses IPv4.
Example architectures
1. A public web application. Route 53 points www.example.com to an internet-facing ALB in two zones. Rules send /api/* to ECS tasks registered by IP and everything else to the web tier. In the S3 vs EBS vs EFS three-tier example, this ALB is what sits in front of the Auto Scaling group.
Clients --HTTPS--> ALB (2+ AZs, WAF, HTTPS listener)
|-- /api/* --> target group: ECS tasks (ip)
'-- default --> target group: EC2 Auto Scaling group (instance)
2. A non-HTTP service with fixed IPs. An internet-facing NLB with an Elastic IP per zone and a TLS listener in front of an MQTT broker or a custom TCP protocol. The NLB has a security group, and the targets’ security group allows traffic only from that group.
Devices --TLS:8883--> NLB (Elastic IP per AZ, TLS listener, security group)
'--> target group: brokers (instance, client IP preserved)
3. A SaaS API that customers reach privately. An internal NLB forwards TCP 443 to an internal ALB (target type alb). A VPC endpoint service on the NLB lets customer VPCs connect through PrivateLink, while the ALB does host-based routing per tenant.
Customer VPC --PrivateLink--> NLB (TCP 443) --> ALB (HTTPS rules) --> services
Hands-on: illustrative AWS CLI commands
Create an ALB with an HTTPS listener and a path rule
aws elbv2 create-load-balancer --name web-alb --type application \
--scheme internet-facing --ip-address-type dualstack \
--subnets subnet-0aaa1111bbbb2222c subnet-0ddd3333eeee4444f \
--security-groups sg-0alb1234567890abc
aws elbv2 create-target-group --name web-api-tg --protocol HTTP --port 8080 \
--vpc-id vpc-0123456789abcdef0 --target-type ip \
--health-check-path /healthz --matcher HttpCode=200
aws elbv2 create-listener --load-balancer-arn <alb-arn> \
--protocol HTTPS --port 443 \
--ssl-policy ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09 \
--certificates CertificateArn=<acm-certificate-arn> \
--default-actions Type=forward,TargetGroupArn=<web-api-tg-arn>
aws elbv2 create-rule --listener-arn <https-listener-arn> --priority 10 \
--conditions Field=path-pattern,Values='/images/*' \
--actions Type=forward,TargetGroupArn=<images-tg-arn>
# Allow longer idle connections (default is 60 seconds)
aws elbv2 modify-load-balancer-attributes --load-balancer-arn <alb-arn> \
--attributes Key=idle_timeout.timeout_seconds,Value=120
Note --subnets with two zones: an ALB needs at least two. dualstack also needs subnets with IPv6 ranges. And note the explicit --ssl-policy; leave it out and the CLI uses ELBSecurityPolicy-2016-08.
Create an NLB with Elastic IPs, a security group and a TLS listener
aws elbv2 create-load-balancer --name tcp-nlb --type network --scheme internet-facing \
--subnet-mappings SubnetId=subnet-0aaa1111bbbb2222c,AllocationId=eipalloc-0a1b2c3d4e5f60001 \
SubnetId=subnet-0ddd3333eeee4444f,AllocationId=eipalloc-0a1b2c3d4e5f60002 \
--security-groups sg-0nlb1234567890abc
aws elbv2 create-target-group --name tcp-app-tg --protocol TCP --port 9000 \
--vpc-id vpc-0123456789abcdef0 --target-type instance --health-check-protocol TCP
aws elbv2 create-listener --load-balancer-arn <nlb-arn> \
--protocol TLS --port 443 \
--ssl-policy ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09 --alpn-policy HTTP2Preferred \
--certificates CertificateArn=<acm-certificate-arn> \
--default-actions Type=forward,TargetGroupArn=<tcp-app-tg-arn>
# Optional: spread traffic across zones (off by default on NLB; adds cross-zone data transfer)
aws elbv2 modify-load-balancer-attributes --load-balancer-arn <nlb-arn> \
--attributes Key=load_balancing.cross_zone.enabled,Value=true
# Keep client IPs and shorten draining for faster deployments
aws elbv2 modify-target-group-attributes --target-group-arn <tcp-app-tg-arn> \
--attributes Key=preserve_client_ip.enabled,Value=true Key=deregistration_delay.timeout_seconds,Value=60
# Raise the TCP idle timeout from the 350-second default
aws elbv2 modify-listener-attributes --listener-arn <tls-listener-arn> \
--attributes Key=tcp.idle_timeout.seconds,Value=900
The --security-groups flag on create is the one you can’t add later. Even if you don’t need rules today, attaching a security group at creation keeps your options open (unless you plan QUIC listeners, which require an NLB without security groups).
Put the ALB behind the NLB
aws elbv2 create-target-group --name alb-behind-nlb --protocol TCP --port 443 \
--target-type alb --vpc-id vpc-0123456789abcdef0 \
--health-check-protocol HTTPS --health-check-path /healthz
aws elbv2 register-targets --target-group-arn <alb-behind-nlb-arn> \
--targets Id=<alb-arn>,Port=443
aws elbv2 create-listener --load-balancer-arn <nlb-arn> --protocol TCP --port 443 \
--default-actions Type=forward,TargetGroupArn=<alb-behind-nlb-arn>
In this layout the NLB listener on 443 is TCP, not TLS: the ALB still terminates HTTPS with its own certificate. (Use a different port, or a second NLB, if the same NLB already has the TLS listener from the previous step on 443.)
Check target health (illustrative output, trimmed):
aws elbv2 describe-target-health --target-group-arn <web-api-tg-arn>
{
"TargetHealthDescriptions": [
{
"Target": { "Id": "10.0.1.25", "Port": 8080, "AvailabilityZone": "us-east-1a" },
"HealthCheckPort": "8080",
"TargetHealth": { "State": "healthy" }
},
{
"Target": { "Id": "10.0.2.41", "Port": 8080, "AvailabilityZone": "us-east-1b" },
"HealthCheckPort": "8080",
"TargetHealth": { "State": "unhealthy", "Reason": "Target.ResponseCodeMismatch",
"Description": "Health checks failed with these codes: [404]" }
}
]
}
A 404 like this usually means the health check path doesn’t exist on that target, not that the network is broken.
Clean up
aws elbv2 delete-load-balancer --load-balancer-arn <nlb-arn> # also deletes its listeners
aws elbv2 deregister-targets --target-group-arn <alb-behind-nlb-arn> --targets Id=<alb-arn>
aws elbv2 delete-load-balancer --load-balancer-arn <alb-arn>
aws elbv2 delete-target-group --target-group-arn <target-group-arn> # repeat for each target group
aws ec2 release-address --allocation-id eipalloc-0a1b2c3d4e5f60001 # repeat for each Elastic IP
Deleting a load balancer deletes its listeners but not its targets: instances keep running and stay registered with their target groups. An ALB can’t be deleted while it is registered with an NLB target group, which is why the deregister step comes first. Release the Elastic IPs you allocated for the NLB once you no longer need them.
Where do Gateway Load Balancer and Classic Load Balancer fit?
Gateway Load Balancer is not an ALB or NLB alternative for applications. It works at layer 3, listens for all IP packets on all ports, and sends them to virtual appliances (firewalls, intrusion detection, deep packet inspection) using GENEVE on port 6081. You reach it through Gateway Load Balancer endpoints in your route tables. Pick it when the requirement is “inspect everything”, not “serve my app”.
Classic Load Balancer is the previous generation. AWS recommends migrating to a current-generation load balancer, which for HTTP workloads usually means ALB and for TCP/SSL workloads usually means NLB. Don’t start new designs on it.
Common mistakes with ALB and NLB
- Creating an NLB without a security group. You can’t add one later. Attach one at creation unless you need QUIC.
- Hard-coding ALB IP addresses. They change. Use the DNS name, an alias record, or put an NLB or Global Accelerator in front for fixed IPs.
- Locking out NLB clients after turning on client IP preservation. Targets now see client IPs. Reference the NLB’s security group in the target security group, or allow the client ranges.
- Expecting path routing, WAF or redirects on an NLB. Those are layer 7 features. Use an ALB, or an NLB in front of an ALB.
- Forgetting NLB cross-zone is off. Uneven targets per zone means uneven load per target. Either balance the zones or turn cross-zone on and accept the data transfer cost.
- Leaving the default TLS policy in scripts. CLI and IaC default to
ELBSecurityPolicy-2016-08. Set the policy you want explicitly. - Planning mutual TLS on an NLB TLS listener. It isn’t supported. Use ALB mutual TLS, or a TCP listener with mTLS on the targets.
- Trusting every
X-Forwarded-Forvalue. Clients can send their own. Use the entries added by your load balancer.
Frequently asked questions
What is the main difference between ALB and NLB?
An Application Load Balancer works at layer 7 and routes each HTTP, HTTPS or gRPC request by host, path, headers or other request details. A Network Load Balancer works at layer 4 and forwards TCP, UDP, TLS or QUIC connections without reading the payload, and it offers a static IP per Availability Zone.
Does an Application Load Balancer have a static IP address?
No. ALB doesn’t support static or Elastic IP addresses, so clients should use its DNS name. If you need fixed IPs in front of HTTP routing, register the ALB as a target of a Network Load Balancer, or put AWS Global Accelerator in front of it.
Can a Network Load Balancer terminate TLS?
Yes. A TLS listener on an NLB terminates TLS with a server certificate and can negotiate HTTP/2 through an ALPN policy. NLB does not support mutual TLS at the load balancer. For mTLS, use an ALB, or use an NLB TCP listener and handle mTLS on the targets.
Do Network Load Balancers support security groups?
Yes, but only if you associate at least one security group when you create the NLB. You can’t add security groups later to an NLB that was created without them. QUIC and TCP_QUIC listeners are not allowed on an NLB that has security groups.
Can I put an ALB behind an NLB?
Yes. Create a target group of type alb with the TCP protocol, register the ALB, and forward an NLB TCP listener to it. Both load balancers must be in the same VPC and account. You get NLB static IPs or PrivateLink in front of ALB layer 7 routing.
Is NLB cheaper than ALB?
It depends on your traffic. Both charge per hour plus capacity units: LCUs for ALB, measured on connections, processed bytes and rule evaluations, and NLCUs for NLB, measured on connections or flows and processed bytes. TLS listeners on NLB use capacity faster than TCP. Model your numbers in the AWS Pricing Calculator.
Sources
All checked on October 16, 2026.
- Elastic Load Balancing: How Elastic Load Balancing works (cross-zone, routing, IP address types), Elastic Load Balancing features and product comparison, Network Load Balancer product page (TLS offloading, certificates), DeleteLoadBalancer API reference, ELB FAQs (cross-zone data transfer)
- Application Load Balancer: What is an Application Load Balancer?, Application Load Balancers (subnets, attributes, idle timeout, IP address types, cross-zone), listeners (WebSockets, HTTP/2), listener rule actions (redirects, fixed responses, weighted target groups), target groups (target types, gRPC, routing algorithms), health checks, X-Forwarded headers, mutual TLS, security policies
- Network Load Balancer: What is a Network Load Balancer?, listeners (protocols, idle timeout, listener rules, mTLS, ALPN), create a listener (QUIC restrictions), target groups (target types, client IP preservation default), target group attributes (client IP, proxy protocol, cross-zone), security groups, Application Load Balancer as a target, health checks, security policies
- Announcements: NLB QUIC passthrough, November 2025, NLB listener rules, July 2026, Introducing QUIC protocol support for Network Load Balancer (AWS blog)
- Other load balancers: What is a Gateway Load Balancer?, What is a Classic Load Balancer?
- AWS Global Accelerator: components (static IP addresses), client IP address preservation
- Pricing: Elastic Load Balancing pricing, AWS Pricing Calculator
Learn AWS networking with guided practice. For live, instructor-led AWS classes with hands-on labs on load balancing, VPCs and architecture, see AWS training. If you are in the United States, see online AWS and AI/ML training in the USA. For more comparisons and labs, browse the AWS tutorials hub.
Newsletter
Enjoyed this post?
Get new posts, AI/ML tutorials, AWS batch dates and Oracle tips by email. No spam, unsubscribe anytime.