ALB vs NLB: Choosing a Load Balancer

6 min read

When you pick a load balancer on AWS, the real choice comes down to two: the Application Load Balancer (ALB) and the Network Load Balancer (NLB). The conclusion up front: ALB is the default for HTTP(S) services; you move to NLB when you need static IPs, non-HTTP protocols, or PrivateLink. Their features overlap enough to cause confusion, but the deciding conditions narrow down to just a few. The basics of both load balancers and attaching ACM certificates are covered in AWS Intermediate #6. Prices are for us-east-1.

Side-by-side comparison #

ALBNLB
LayerL7 (HTTP/HTTPS, gRPC)L4 (TCP/UDP/TLS)
RoutingPath, host, and header rulesNone (listener port → target group)
Static IPNo (DNS name only)Fixed IP per AZ, EIP supported
Source IPPassed via X-Forwarded-For headerPreserved in the packet
Target typesInstance, IP, LambdaInstance, IP, ALB
Hourly rate~$0.0225~$0.0225
Capacity unit~$0.008 per LCU~$0.006 per NLCU

L7 vs L4: reading the request or passing it through #

ALB is the load balancer that reads the request and makes decisions. It inspects the path (/api/*), host (admin.example.com), headers, and query string, and routes to different target groups. It handles HTTP redirects and fixed responses at the load balancer itself, enforces login in front of your backend via Cognito and OIDC authentication, and connects directly to WAF. It supports HTTP/2, gRPC, and WebSocket, and can even use Lambda functions as targets. Serving multiple microservices behind a single load balancer is ALB’s home turf.

NLB is the load balancer that forwards packets without opening them. There are no routing rules, but the shorter processing path keeps added latency below the millisecond range, and it absorbs millions of requests per second and sudden traffic spikes without warm-up. It supports TCP, UDP, and TLS listeners, so for non-HTTP traffic — game servers, MQTT brokers, DNS, database proxies — NLB is the only option to begin with.

What only NLB can do #

  • Static IPs: NLB has a fixed IP per AZ and lets you assign EIPs directly. For enterprise integrations that require registering IPs in a firewall allowlist, this single condition settles the choice. ALB only provides a DNS name, and its IPs change over time.
  • Source IP preservation: behind NLB, the client IP stays in the packet as-is. Behind ALB, your application has to be modified to read the X-Forwarded-For header.
  • PrivateLink: exposing a service to other accounts as a VPC endpoint service requires NLB. ALB cannot be the entry point of PrivateLink on its own.
  • TLS passthrough: requirements that keep encryption intact all the way to the backend (end-to-end encryption audits and the like) are only possible with NLB passing traffic through a TCP listener. NLB can also terminate TLS with an ACM certificate if you want it to.

A few misconceptions in the other direction are worth clearing up. Security groups used to be ALB-only, but NLB has supported them since 2023, so this is no longer a differentiator. Both support health checks, and NLB additionally offers TCP health checks (verifying the port is open).

Pricing: same hourly rate, diverging at the LCU #

Both cost about $0.0225 per hour — roughly $16 a month even with zero traffic. The difference is the capacity unit charge. ALB bills about $0.008 per LCU and NLB about $0.006 per NLCU, but what matters more than the unit price is how much capacity one unit holds:

  • One LCU (ALB): 25 new connections/sec, 3,000 active connections, 1GB/hour processed, or 1,000 rule evaluations/sec — billed on whichever dimension you use most
  • One NLCU (NLB, TCP): 800 new connections/sec, 100,000 active connections, 1GB/hour processed

By new connections, one NLCU holds 32 times what an LCU does. Connection-heavy workloads with many short connections (polling clients, tens of thousands of IoT devices) see a much smaller NLB bill for the same traffic. If connections are few and bandwidth dominates, both sides hit the processed-bytes dimension (1GB/hour) and the difference is marginal. Check which dimension you land on with the ConsumedLCUs metric in CloudWatch.

The hidden cost is cross-zone load balancing. It is on by default for ALB with no inter-AZ transfer charge, but off by default for NLB — and turning it on adds inter-AZ data transfer fees. Enable it casually during an NLB migration and it becomes one of those line items that suddenly grow your bill. On the ALB side, the trap is the idle timeout (60 seconds by default): slow responses and long polling get cut off with a 504 unless you raise it.

If you need both: chain NLB → ALB #

If you need static IPs but also want path-based routing, you don’t have to choose. NLB supports ALB as a target type, so you can build the chain NLB (static IP, PrivateLink) → ALB (L7 routing) → services. You pay for two load balancers, so this is strictly for when both requirements genuinely coexist; if one of them is absent, a single load balancer is the right call.

Selection order #

  1. Start with the protocol: anything other than HTTP(S) or gRPC settles it for NLB. ALB cannot handle TCP, UDP, or TLS passthrough.
  2. Check static IP and PrivateLink requirements: if you need allowlist registration or VPC endpoint service exposure, it’s NLB.
  3. Assess the need for L7 features: path and host routing, authentication, WAF, or Lambda targets mean ALB. The typical case is multiple container services behind one entry point (the front end of the services discussed in ECS Fargate vs EC2).
  4. If both, consider the chain: an NLB → ALB setup satisfies both requirements at once.
  5. Sanity-check the bill by LCU dimension: connection-heavy favors NLB; bandwidth-heavy is roughly a tie. The hourly fixed cost is identical either way, so also make sure no unused load balancers are sitting around (standing checklist).

Summary #

  • ALB is the default for HTTP(S) services. The L7 features — path and host routing, authentication, WAF, Lambda targets — all live on the ALB side.
  • If any of static IPs, source IP preservation, PrivateLink, TLS passthrough, or non-HTTP protocols apply, it’s NLB.
  • The hourly rate is the same ~$0.0225 for both; bills diverge in the LCU math. New-connection capacity differs by 32x, so connection-heavy workloads favor NLB.
  • NLB’s cross-zone load balancing is off by default and adds inter-AZ transfer fees when enabled. ALB defaults to a 60-second idle timeout.
  • When you need static IPs and L7 routing at the same time, chain NLB → ALB.
X