AWS Load Balancers: ALB vs NLB vs CLB Complete Guide (2026)
AWS offers three active load balancer types: Application Load Balancer (ALB) for HTTP/HTTPS Layer 7 routing, Network Load Balancer (NLB) for Layer 4 ultra-low latency TCP/UDP, and the legacy Classic Load Balancer (CLB). Choosing the right one — and configuring it correctly — directly impacts your application's performance, availability, and cost.
Table of Contents
1. ALB vs NLB vs CLB
| Feature | ALB | NLB | CLB |
|---|---|---|---|
| OSI Layer | 7 (HTTP/HTTPS) | 4 (TCP/UDP/TLS) | 4 and 7 |
| Path routing | ✅ | ❌ | ❌ |
| Host routing | ✅ | ❌ | ❌ |
| Static IP | ❌ (use NLB→ALB) | ✅ per AZ | ❌ |
| WebSocket | ✅ | ✅ | ❌ |
| gRPC | ✅ | ✅ | ❌ |
| Lambda targets | ✅ | ❌ | ❌ |
| Latency | ~400ms overhead | ~100µs overhead | Medium |
| Status | Current | Current | Legacy |
2. Application Load Balancer (ALB)
Create an ALB with path-based routing via AWS CLI:
# Create ALB
aws elbv2 create-load-balancer \
--name myapp-alb \
--subnets subnet-public-1a subnet-public-1b \
--security-groups sg-alb-external \
--scheme internet-facing \
--type application
# Create target groups
aws elbv2 create-target-group \
--name myapp-api-tg \
--protocol HTTP \
--port 8080 \
--vpc-id vpc-0abc1234 \
--health-check-path /actuator/health \
--health-check-interval-seconds 30 \
--healthy-threshold-count 2 \
--unhealthy-threshold-count 3
aws elbv2 create-target-group \
--name myapp-frontend-tg \
--protocol HTTP \
--port 3000 \
--vpc-id vpc-0abc1234 \
--health-check-path /
# Create HTTPS listener with routing rules
LISTENER_ARN=$(aws elbv2 create-listener \
--load-balancer-arn $ALB_ARN \
--protocol HTTPS --port 443 \
--certificates CertificateArn=arn:aws:acm:us-east-1:123456789:certificate/abc123 \
--default-actions Type=forward,TargetGroupArn=$FRONTEND_TG_ARN \
--query 'Listeners[0].ListenerArn' --output text)
# Add path-based rule for API
aws elbv2 create-rule \
--listener-arn $LISTENER_ARN \
--priority 10 \
--conditions Field=path-pattern,Values='/api/*' \
--actions Type=forward,TargetGroupArn=$API_TG_ARN
Weighted target groups for canary deployments — send 10% to v2:
aws elbv2 modify-rule \
--rule-arn $RULE_ARN \
--actions Type=forward,ForwardConfig='{
"TargetGroups": [
{"TargetGroupArn": "'$API_V1_TG_ARN'", "Weight": 90},
{"TargetGroupArn": "'$API_V2_TG_ARN'", "Weight": 10}
],
"StickinessDuration": 3600
}'
3. Network Load Balancer (NLB)
# Create NLB with static Elastic IPs
aws elbv2 create-load-balancer \
--name myapp-nlb \
--type network \
--scheme internet-facing \
--subnet-mappings \
SubnetId=subnet-1a,AllocationId=eipalloc-111 \
SubnetId=subnet-1b,AllocationId=eipalloc-222
# TCP listener on port 443 (TLS passthrough to targets)
aws elbv2 create-listener \
--load-balancer-arn $NLB_ARN \
--protocol TCP --port 443 \
--default-actions Type=forward,TargetGroupArn=$NLB_TG_ARN
4. Target Groups and Health Checks
Well-tuned health checks prevent routing to unhealthy instances:
aws elbv2 modify-target-group \
--target-group-arn $TG_ARN \
--health-check-protocol HTTP \
--health-check-path /actuator/health/liveness \
--health-check-interval-seconds 15 \
--health-check-timeout-seconds 5 \
--healthy-threshold-count 2 \
--unhealthy-threshold-count 2 \
--matcher HttpCode=200
# Register targets (EC2 instances)
aws elbv2 register-targets \
--target-group-arn $TG_ARN \
--targets Id=i-instance1 Id=i-instance2
5. SSL/TLS Termination
Use ACM (AWS Certificate Manager) for free SSL certificates. Key settings:
- Redirect HTTP → HTTPS: Add a port 80 listener with redirect action to port 443
- Security policy: Use
ELBSecurityPolicy-TLS13-1-2-2021-06— requires TLS 1.2+, supports TLS 1.3 - Multiple certificates: ALB supports SNI — attach multiple ACM certs for multiple domains
# HTTP → HTTPS redirect listener
aws elbv2 create-listener \
--load-balancer-arn $ALB_ARN \
--protocol HTTP --port 80 \
--default-actions \
Type=redirect,RedirectConfig='{Protocol=HTTPS,Port=443,StatusCode=HTTP_301}'
6. WAF Integration
# Associate WAF Web ACL with ALB
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:123456789:regional/webacl/MyWebACL/abc123 \
--resource-arn $ALB_ARN
7. Access Logs
# Enable access logs to S3
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn $ALB_ARN \
--attributes \
Key=access_logs.s3.enabled,Value=true \
Key=access_logs.s3.bucket,Value=myapp-alb-logs \
Key=access_logs.s3.prefix,Value=prod-alb \
Key=idle_timeout.timeout_seconds,Value=60 \
Key=routing.http2.enabled,Value=true
Frequently Asked Questions
When should I use NLB instead of ALB?
Use NLB when: you need a static IP address (for allowlisting by customers), you need ultra-low latency (gaming, financial trading), you're handling non-HTTP protocols (TCP, UDP), or you need to handle millions of requests per second. For standard web apps, ALB is almost always the right choice.
How do I get a static IP for my ALB?
ALBs don't support static IPs directly. The pattern is: put an NLB in front of the ALB. NLB gets static Elastic IPs, and you configure the NLB to forward to the ALB's DNS name. Alternatively, use Global Accelerator which provides static Anycast IPs backed by the ALB.
What is connection draining / deregistration delay?
When you deregister a target, the load balancer stops sending new requests but waits (default 300 seconds) for in-flight requests to complete before removing the target. Tune this to your request duration — for microservices with fast requests, 30–60 seconds is usually enough.
How do I troubleshoot 5xx errors from ALB?
502 = target returned invalid response or is unreachable. 503 = no healthy targets. 504 = target didn't respond within the idle timeout. Check: target health in the console, target security group allows ALB SG on the app port, application logs for errors, and CloudWatch access logs for detailed error info.