ALB vs NLB: Key Differences Between Application Load Balancer and Network Load Balancer
Choosing between an Application Load Balancer and a Network Load Balancer is one of the first architectural decisions you'll face when deploying a web application on AWS — and picking the wrong one creates routing limitations that are painful to undo after traffic is live.
TL;DR: ALB vs NLB at a Glance
| Dimension | Application Load Balancer (ALB) | Network Load Balancer (NLB) |
|---|---|---|
| OSI Layer | Layer 7 (Application) | Layer 4 (Transport) |
| Protocols | HTTP, HTTPS, gRPC, WebSocket | TCP, UDP, TLS, TCP_UDP |
| Routing Logic | Host, path, header, query string, method | IP address, port, protocol |
| Client IP Visibility | X-Forwarded-For header | Native source IP preservation (with target type ip) |
| Static IP / Elastic IP | Not supported natively | Supported per AZ |
| TLS Termination | Yes (ACM integration) | Yes (ACM integration) |
| Primary Use Case | Web apps, microservices, API routing | High-performance TCP/UDP, firewall traversal, static IP requirements |
How AWS Elastic Load Balancing Works: The OSI Layer Split
Both ALB and NLB are managed load balancers under the AWS Elastic Load Balancing (ELB) service, but they intercept traffic at fundamentally different layers of the network stack. An ALB terminates the HTTP connection at the load balancer itself — it reads the full request, applies routing rules, then opens a new connection to the target. An NLB operates below the HTTP layer: it routes TCP/UDP flows based on connection-level attributes without inspecting the payload, which means the connection can be passed through with minimal processing overhead. This architectural split is what drives every practical difference between the two.
Layer 7 — HTTP Termination"] DNS --> NLB_Path["NLB Node
Layer 4 — TCP/UDP Flow"] ALB_Path --> RuleEngine["Listener Rule Engine
host / path / header / method"] RuleEngine --> TG_A["Target Group A
/api/* → Port 8080"] RuleEngine --> TG_B["Target Group B
/* → Port 80"] NLB_Path --> TCP_Forward["TCP Flow Forwarded
Source IP Preserved"] TCP_Forward --> TG_C["Target Group C
Port 8883"] style ALB_Path fill:#4a90d9,color:#fff style NLB_Path fill:#e07b39,color:#fff style RuleEngine fill:#2d6a9f,color:#fff
- Client Request: A browser or API client initiates a connection to the load balancer's DNS endpoint.
- ALB Path (Layer 7): The ALB terminates the TCP and TLS connection, reads the HTTP request line and headers, evaluates listener rules (host, path, header conditions), and forwards to the matched target group over a new connection.
- NLB Path (Layer 4): The NLB routes the TCP/UDP flow based on the 5-tuple (source IP, source port, destination IP, destination port, protocol) without reading the payload. The connection is forwarded to a target, preserving the source IP when using
iporinstancetarget types. - Target Groups: Both load balancers route to target groups containing EC2 instances, IP addresses, Lambda functions (ALB only), or another load balancer (NLB targets ALB).
Application Load Balancer: Layer 7 Routing for Web Applications
The ALB is the right default for any HTTP/HTTPS workload. Its listener rules engine is the core differentiator — you can route a single listener on port 443 to dozens of different target groups based on conditions evaluated against the request.
ALB Listener Rule Conditions
ALB rules support the following condition types, which can be combined with AND logic within a single rule:
- Host header — route
api.example.comandapp.example.comto separate target groups from one listener - Path pattern — route
/api/*to a backend service and/static/*to a different target - HTTP header — route based on custom headers (e.g.,
X-Version: v2) - HTTP request method — separate GET and POST traffic
- Query string — route based on query parameters
- Source IP — restrict access by CIDR
This is the capability that makes ALB the natural fit for microservices: one ALB, one DNS name, one TLS certificate — and the routing logic lives in the load balancer rather than in application code or a separate reverse proxy.
ALB CLI: Creating a Path-Based Routing Rule
🔽 Click to expand — ALB path-based routing setup
# 1. Create the ALB
aws elbv2 create-load-balancer \
--name my-web-alb \
--subnets subnet-0abc1234 subnet-0def5678 \
--security-groups sg-0abc1234 \
--scheme internet-facing \
--type application \
--ip-address-type ipv4
# 2. Create two target groups
aws elbv2 create-target-group \
--name api-targets \
--protocol HTTP \
--port 8080 \
--vpc-id vpc-0abc1234 \
--target-type instance
aws elbv2 create-target-group \
--name web-targets \
--protocol HTTP \
--port 80 \
--vpc-id vpc-0abc1234 \
--target-type instance
# 3. Create HTTPS listener with default action
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-web-alb/1234567890abcdef \
--protocol HTTPS \
--port 443 \
--certificates CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/abcd1234-ef56-7890-abcd-ef1234567890 \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/web-targets/abcdef1234567890
# 4. Add path-based rule to route /api/* to api-targets
aws elbv2 create-rule \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/my-web-alb/1234567890abcdef/abcdef1234567890 \
--priority 10 \
--conditions Field=path-pattern,Values='/api/*' \
--actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/api-targets/1234567890abcdef
IAM Policy for ALB Management
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateRule",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeRules"
],
"Resource": "*"
}
]
}
Note: Several Describe/List actions require "Resource": "*" — resource-level restrictions are not supported for those actions. Verify in the Service Authorization Reference before narrowing scope.
Network Load Balancer: Layer 4 Routing for Performance and Protocol Flexibility
The NLB is not a "faster ALB" — it's a fundamentally different tool for different problems. The moment your requirements include a static IP address, non-HTTP protocols, or sub-millisecond latency sensitivity, the NLB becomes the correct choice.
When NLB Is the Right Answer
- Static or Elastic IP per AZ: NLB supports assigning an Elastic IP address to each load balancer node. This is required for firewall allowlisting by IP, which ALB cannot satisfy because its IP addresses change.
- Non-HTTP protocols: UDP-based workloads (DNS, syslog, gaming), raw TCP services (databases, MQTT brokers), and custom binary protocols have no HTTP layer for ALB to inspect.
- Source IP preservation: When using
iporinstancetarget types, NLB preserves the client's source IP address at the network level — no header injection required. - PrivateLink: AWS PrivateLink endpoint services require an NLB as the front-end load balancer.
- NLB in front of ALB: A common pattern combines both — NLB provides static IPs and handles TLS passthrough or TCP routing, then forwards to an ALB for Layer 7 routing logic.
NLB CLI: Creating a TCP Listener
🔽 Click to expand — NLB TCP listener setup
# 1. Create the NLB with an Elastic IP per subnet
aws elbv2 create-load-balancer \
--name my-tcp-nlb \
--type network \
--scheme internet-facing \
--subnet-mappings SubnetId=subnet-0abc1234,AllocationId=eipalloc-0abc1234 \
SubnetId=subnet-0def5678,AllocationId=eipalloc-0def5678
# 2. Create a TCP target group
aws elbv2 create-target-group \
--name tcp-targets \
--protocol TCP \
--port 8883 \
--vpc-id vpc-0abc1234 \
--target-type instance
# 3. Create a TCP listener on port 8883
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/my-tcp-nlb/1234567890abcdef \
--protocol TCP \
--port 8883 \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/tcp-targets/abcdef1234567890
The Misdiagnosis That Costs Hours: Security Groups on NLB
Here's a failure pattern that catches engineers who migrate from ALB to NLB: traffic stops reaching targets, health checks fail, but the NLB console shows the load balancer as active. The instinct is to check the NLB security group — but NLBs did not support security groups for most of their history. Traffic was controlled entirely at the target's security group level, and the NLB passed source IPs through directly.
AWS introduced security group support for NLBs in 2023. If your NLB was created before that feature was enabled in your account, or if no security group is attached, inbound filtering happens only at the target instance's security group — and that security group must allow traffic from the client's IP range, not from the NLB's IP. Engineers who copy ALB security group rules (allowing traffic from the ALB's security group ID) to an NLB setup will see silent drops because the NLB doesn't have a security group ID to reference in the target's inbound rule.
Think of the NLB without a security group as a transparent patch panel: it forwards packets without stamping its own identity on them. The target sees the client's IP, not the load balancer's.
Verify whether your NLB has a security group attached:
aws elbv2 describe-load-balancers \
--names my-tcp-nlb \
--query 'LoadBalancers[*].{Name:LoadBalancerName,SecurityGroups:SecurityGroups,Type:Type}'
If SecurityGroups is empty, your target security groups must allow inbound traffic from the client CIDR ranges directly — not from a load balancer security group reference.
Decision Guide: ALB vs NLB for Your Application Load Balancer Choice
for firewall allowlist?"} Q1 -- No --> Q3{"Need AWS PrivateLink?"} Q2 -- No --> ALB["Use ALB
Layer 7 routing"] Q2 -- Yes --> Q4{"Need content-based
routing too?"} Q4 -- No --> NLB["Use NLB
Static IP + TCP"] Q4 -- Yes --> COMBO["NLB → ALB Pattern
Static IP + HTTP routing"] Q3 -- Yes --> NLB2["Use NLB
PrivateLink requires NLB"] Q3 -- No --> NLB3["Use NLB
TCP / UDP / TLS protocol"] style ALB fill:#2e7d32,color:#fff style NLB fill:#e07b39,color:#fff style NLB2 fill:#e07b39,color:#fff style NLB3 fill:#e07b39,color:#fff style COMBO fill:#6a1b9a,color:#fff
- Start with protocol: If the workload is HTTP/HTTPS/gRPC, ALB is the default path. Non-HTTP protocols route to NLB.
- Static IP requirement: If firewall teams require a fixed IP allowlist, NLB is mandatory regardless of protocol.
- PrivateLink: AWS PrivateLink endpoint services require NLB — no alternative.
- Content-based routing: If routing decisions depend on URL path, hostname, or HTTP headers, only ALB supports this natively.
- Combined pattern: Static IP + HTTP routing = NLB (TCP) → ALB. This is a supported and documented AWS architecture.
Wrap-Up: Choosing the Right AWS Load Balancer
For most web applications, the Application Load Balancer is the correct starting point — its Layer 7 routing capabilities, native HTTPS termination, and HTTP/2 and gRPC support cover the majority of web and API workloads. Reach for the Network Load Balancer when your requirements include static IPs, non-HTTP protocols, AWS PrivateLink, or extreme throughput sensitivity at the transport layer.
The two are not mutually exclusive. The NLB-in-front-of-ALB pattern is a documented AWS architecture that gives you both static IPs and content-based routing when you need both.
Glossary
| Term | Definition |
|---|---|
| OSI Layer 7 | The Application layer of the OSI model — where HTTP, HTTPS, and gRPC operate. ALB inspects traffic at this layer. |
| OSI Layer 4 | The Transport layer — where TCP and UDP connections are established. NLB routes at this layer without reading payload content. |
| Target Group | A logical grouping of targets (EC2 instances, IPs, Lambda functions) that a load balancer routes requests to. Health checks are configured per target group. |
| Listener Rule | An ALB-specific configuration that evaluates conditions on incoming requests and routes them to a target group or returns a fixed response. |
| AWS PrivateLink | A service that enables private connectivity between VPCs and AWS services without traversing the public internet. Requires an NLB as the endpoint service front-end. |
Comments
Post a Comment