NLB vs ALB
One-liner#
NLB is an L4 (TCP/UDP) load balancer; ALB is an L7 (HTTP/HTTPS) load balancer. NLB forwards packets as-is, while ALB parses HTTP requests before routing them.
How Each Layer Works#
NLB (L4):
Client → [NLB: forward TCP packet] → Server
- Does not inspect packet contents
- Routes by IP + Port only
ALB (L7):
Client → [ALB: parse HTTP request] → Server
- Inspects Host header, URL path, HTTP method
- Makes routing decisions based on request content
Key Differences#
| NLB | ALB | |
|---|---|---|
| OSI layer | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| Routing basis | IP + Port | Host, Path, Header, Method |
| Latency | ~100µs (ultra-low) | ~1ms |
| Static IP | Yes (1 per AZ) | No (DNS-based) |
| Throughput | Millions of requests/sec | Tens of thousands of requests/sec |
| Protocols | TCP, UDP, TLS | HTTP, HTTPS, gRPC, WebSocket |
Routing Capabilities#
NLB:
- Port-based routing only
- :443 → Target Group A
- :8080 → Target Group B
ALB:
- api.example.com/users → User service
- api.example.com/orders → Order service
- admin.example.com/* → Admin service
- Header X-Version: v2 → V2 service
With ALB, a single load balancer can route to multiple services by Host or Path. With NLB, you’d have to split by port or deploy separate NLBs.
Performance#
NLB is significantly faster:
| NLB | ALB | |
|---|---|---|
| Latency | ~100µs | ~1ms (10× slower) |
| Warm-up | Not required | May be needed under sudden traffic spikes |
| Connections/sec | Millions | Tens of thousands |
NLB simply forwards packets without inspecting them. ALB has overhead from HTTP parsing, header inspection, and routing rule evaluation.
Static IP#
NLB:
AZ-a: 52.78.xxx.xxx (fixed)
AZ-c: 13.125.xxx.xxx (fixed)
→ Great for IP allowlists
ALB:
k8s-staging-xxxx.ap-northeast-2.elb.amazonaws.com
→ IP changes (DNS-based)
→ Cannot be IP-allowlisted; must use the domain
If a partner says “we need to whitelist your IP in our firewall,” you need NLB.
Security Group — The Deciding Factor for ALB#
Blocking direct access in a CloudFront → LB architecture#
The whole point of putting CloudFront in front is DDoS protection and WAF. If an attacker discovers the ALB endpoint and bypasses CloudFront, that protection is meaningless. This exact attack came up in a penetration test (H-10).
Normal flow: User → CloudFront (WAF inspection) → ALB → Pod ✅
Bypass attack: Attacker → ALB directly (WAF bypassed) → Pod ❌ must block
To prevent this, the ALB must only accept traffic originating from CloudFront.
ALB: solved with Security Group + Prefix List#
CloudFront receives requests at edge locations worldwide and forwards them to the origin (ALB). AWS manages the IP ranges of those edge servers as a Managed Prefix List (pl-22a6434b) — roughly 45 IP ranges, automatically kept up to date.
ALB Security Group:
Inbound rules:
443 ← pl-22a6434b (CloudFront edge IPs, ~45 ranges)
443 ← 39.119.192.15/32 (Team member A)
443 ← 124.49.102.36/32 (Team member B)
443 ← 122.34.166.131/32 (Team member C)
Result:
Requests from CloudFront edge → Allowed ✅
Direct access from team member IPs → Allowed ✅
Attacker hitting the ALB endpoint → Blocked ❌ (IP not in SG)
Because ALB has full Security Group support, you can apply a Prefix List directly.
NLB: limited Security Group support#
NLB originally had no Security Group support at all. Support was added in 2023, but with constraints:
| Condition | NLB SG support |
|---|---|
| Target type: IP | Supported |
| Target type: Instance | Not supported |
| Target type: ALB | Not supported |
| Adding SG to an existing NLB | Not possible (only at creation) |
In EKS environments, the AWS Load Balancer Controller often creates NLBs with Instance target type, which means you can’t attach a Security Group.
NLB (Instance targets):
SG cannot be attached
→ Cannot apply the CloudFront Prefix List
→ Anyone can reach the NLB endpoint directly
→ The CloudFront + WAF security chain is effectively broken
Summary comparison#
| NLB | ALB | |
|---|---|---|
| SG support | Added 2023, target type restrictions | Full support |
| Prefix List | Conditional (IP targets only) | Works out of the box |
| Block direct access bypassing CloudFront | Difficult or impossible | One line with pl-22a6434b |
| Result | Gap in security chain | Complete security chain |
This difference is the decisive reason ALB was chosen over NLB. No matter how good NLB’s ~100µs latency is, if you can’t build the CloudFront → WAF → SG security chain, it isn’t viable for a ticketing platform.
AWS Service Integrations#
| Service | NLB | ALB |
|---|---|---|
| CloudFront Origin | Restricted | Direct connection |
| AWS WAF | ✗ (L4, no HTTP parsing) | ✓ |
| ACM certificate | Manual management | Automatic integration |
| Cognito auth | ✗ | ✓ |
ALB is required to build the security chain (CloudFront → WAF → LB → backend).
Cost (ap-northeast-2)#
| NLB | ALB | |
|---|---|---|
| Hourly fixed | $0.0225 | $0.0225 |
| Processing unit | NLCU $0.006 | LCU $0.008 |
| Public IP | Static IP included | Auto-assigned $0.005/h/IP |
| Est. monthly (2 AZ) | ~$16 | ~$23 (incl. IPs) |
ALB is slightly more expensive, but the difference is not significant.
When to Use Each#
Use NLB when#
- A static IP is required (partner allowlist)
- Direct TCP/UDP handling (DB, messaging, game servers)
- Ultra-low latency matters (real-time trading)
- Exposing services via PrivateLink
- Handling massive concurrent connections
Use ALB when#
- Host/Path-based routing (multiple MSA services)
- CloudFront + WAF security chain
- HTTP redirects or fixed responses
- gRPC routing (in front of Istio)
- Cognito authentication integration
Real-world Experience#
In the PlayBall project, NLB was considered initially — L4 performance seemed advantageous for the burst of traffic at ticket sale opens.
However, once CloudFront was placed in front, we switched from NLB to ALB:
- CloudFront origin integration: ALB connects directly by DNS; NLB has restrictions
- Security Group: Applied the CloudFront Prefix List to the ALB SG to block direct access
- AWS WAF integration: WAF can only be attached directly to ALB
- Host-based routing: Multiple services (API, Grafana, ArgoCD) routed through a single ALB
The ~1ms latency of ALB was imperceptible in practice, thanks to CloudFront caching and Istio’s internal routing.