Network Load Balancer in Depth
The Network Load Balancer (NLB) is the member of the Elastic Load Balancing (ELB) family built for raw speed. While an Application Load Balancer (ALB) understands HTTP and reads request headers, the NLB works one layer lower in the network and simply forwards connections. That makes it dramatically faster, gives it features the ALB cannot offer (like static IP addresses), and also means it behaves quite differently — so the instincts you built with an ALB do not all carry over.
What “layer 4” actually means
Networks are often described as a stack of layers (the OSI model). Layer 7 is the application layer, where protocols like HTTP and HTTPS live. Layer 4 is the transport layer, where TCP (Transmission Control Protocol, the reliable connection protocol behind most internet traffic) and UDP (User Datagram Protocol, a faster, connectionless protocol used for things like DNS, gaming, and streaming) live.
An NLB operates at layer 4. It does not open up your packets or read HTTP paths, hostnames, or cookies. It just looks at the destination IP address and port, picks a healthy target, and forwards the connection. Because it never inspects the content, it can handle millions of requests per second at very low latency, and it scales to sudden traffic spikes without any “pre-warming.”
The NLB supports three listener protocols:
| Protocol | What it carries | Typical use |
|---|---|---|
| TCP | Any reliable connection-based traffic | Databases, custom binary protocols, generic services |
| UDP | Connectionless traffic | DNS, VoIP, game servers, IoT telemetry |
| TLS | Encrypted TCP, terminated at the NLB | High-throughput HTTPS or secure custom protocols |
When you use a TLS listener, the NLB does the encryption work (decrypting traffic using a certificate from AWS Certificate Manager). With a plain TCP listener, encrypted traffic passes straight through to your targets untouched (called TLS passthrough).
When only an NLB fits
Reach for an NLB — and rule out an ALB — when any of these are true:
- You need a static IP address. An NLB gives you one fixed private IP per Availability Zone (AZ, an isolated datacenter location within a Region), and you can attach an Elastic IP (a permanent public IP address you own) to each. ALBs only give you DNS names, not fixed IPs. This matters when clients have firewall allow-lists that only permit specific IPs.
- Your traffic is not HTTP. Databases, MQTT, raw TCP, or UDP traffic cannot go through an ALB at all.
- You need extreme throughput or the lowest possible latency. An NLB adds far less latency than an ALB because it does no application-layer processing.
- You must preserve the real client IP all the way to the target (see the gotcha below).
- You front a PrivateLink service. AWS PrivateLink (private connectivity between VPCs without crossing the public internet) requires an NLB or a Gateway Load Balancer as its entry point.
If you instead need path-based routing (/api vs /images), host-based routing, redirects, or cookie-based stickiness, you want an ALB — the NLB cannot do any of that.
Tip: You do not have to choose forever. A common pattern is an NLB in front that gives you a static IP, forwarding to an ALB behind it that does the smart HTTP routing. This gives you both fixed IPs and layer-7 features.
The source-IP gotcha (read this before you debug for an hour)
This is the single biggest surprise for engineers moving from an ALB. An NLB preserves the client’s original source IP address. The connection your target instance sees comes from the real client, not from the load balancer.
With an ALB the opposite is true: the ALB is a full proxy, so targets see the ALB’s IP and you allow the ALB’s security group. If you carry that habit to an NLB, every request gets blocked and health checks may still pass, leaving you baffled.
What this means in practice:
- Your target’s security group (a virtual firewall,
sg-0a1b2c3d) must allow the real client IP ranges, not the NLB. For a public service that often means allowing0.0.0.0/0on the app port, scoped carefully. - Health checks come from the NLB nodes’ subnet IP ranges, so you must also allow the VPC CIDR (the IP range of your
vpc-0a1b2c3d) for the health-check port. - Network ACLs (subnet-level firewalls) must permit the client IPs too.
Warning: Because the NLB is not a proxy, you cannot simply “allow the load balancer” on your targets the way you do with an ALB. Allow the actual client traffic, or all connections silently fail.
Health checks behave differently too
An NLB can run health checks at layer 4 (a TCP check that just confirms a port accepts a connection) or at layer 7 (an HTTP/HTTPS check against a path like /health). A passing TCP check only proves the port is open — not that your app is actually serving requests — so prefer an HTTP health check when your target speaks HTTP. NLB health checks also have their own thresholds and intervals; do not assume the ALB defaults apply.
Creating an NLB
Console steps
- Open the EC2 console and choose Load Balancers in the left menu.
- Click Create load balancer, then under Network Load Balancer click Create.
- Enter a name (for example
prod-nlb), choose Internet-facing or Internal, and pick IPv4. - Under Network mapping, select your VPC and tick each AZ. For each AZ, choose the subnet and either let AWS assign an IP or pick Use an Elastic IP and select one (for example
eipalloc-0a1b2c3d). - Under Listeners and routing, add a
TCPlistener on port443and point it at a target group (create one if needed — register your instances such asi-0a1b2c3d4e5f). - Click Create load balancer.
CLI equivalent
# 1. Create the load balancer with an Elastic IP per AZ
aws elbv2 create-load-balancer \
--name prod-nlb \
--type network \
--scheme internet-facing \
--subnet-mappings SubnetId=subnet-0a1b2c3d,AllocationId=eipalloc-0a1b2c3d
# 2. Create a target group with an HTTP health check
aws elbv2 create-target-group \
--name prod-nlb-tg \
--protocol TCP --port 443 \
--vpc-id vpc-0a1b2c3d \
--health-check-protocol HTTP --health-check-path /health
# 3. Register a target
aws elbv2 register-targets \
--target-group-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/prod-nlb-tg/abc123 \
--targets Id=i-0a1b2c3d4e5f
# 4. Create the listener
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/prod-nlb/def456 \
--protocol TCP --port 443 \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/prod-nlb-tg/abc123
Output:
{
"LoadBalancers": [
{
"LoadBalancerArn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/prod-nlb/def456",
"DNSName": "prod-nlb-def456.elb.us-east-1.amazonaws.com",
"Type": "network",
"Scheme": "internet-facing",
"State": { "Code": "provisioning" }
}
]
}
A cost note
An NLB is billed per hour plus a usage charge measured in NLB Capacity Units (NLCUs), which combine new connections, active connections, processed bytes, and rule evaluations. As a rough guide, a steady, low-traffic NLB costs around 16-20 USD per month plus data charges, similar in scale to an ALB. Each Elastic IP attached to a running NLB is free while in use, but unattached Elastic IPs are billed hourly — so release any you no longer need.
Best practices
- Always enable cross-zone load balancing if your AZs hold uneven numbers of targets (note: for NLB this can incur inter-AZ data transfer charges, so weigh it against your traffic shape).
- Use an HTTP/HTTPS health check rather than a bare TCP check whenever your target speaks HTTP, so a hung-but-listening app is caught.
- Configure target security groups for the real client IPs plus the VPC CIDR for health checks — never just “the load balancer.”
- Attach Elastic IPs when clients need a stable allow-list entry, and document those IPs for downstream firewall owners.
- Terminate TLS at the NLB only when you need the throughput; use TCP passthrough when targets must do their own decryption.
- Put an ALB behind the NLB when you need both a static IP and layer-7 routing.