Some workloads do not fit an Application Load Balancer. A database proxy, an MQTT broker, a game server on UDP, a firewall that allowlists IP addresses - none of these want Layer 7 HTTP routing. They want raw Layer 4 forwarding, the lowest possible latency, and often a fixed IP address. That is the Network Load Balancer.
This page provisions an NLB from the SDK: choosing static or Elastic IPs with SubnetMappings, adding TCP and UDP listeners, and pointing them at target groups. Everything uses the same elbv2 / @aws-sdk/client-elastic-load-balancing-v2 client as the ALB, just with different protocols and addressing.
Create the NLB with Type: "network". To get fixed addressing, use SubnetMappings (not Subnets) with an AllocationId per subnet pointing at a pre-allocated Elastic IP.
Allocate the Elastic IPs first with EC2's AllocateAddress. For an internal NLB you instead pass PrivateIPv4Address per subnet mapping to pin a specific in-VPC address. Either way, the address stays put for the life of the load balancer, which is exactly what a firewall allowlist or a hardcoded client config needs.
An NLB target group uses a Layer 4 protocol, and its health check can still be HTTP even though the traffic is raw TCP. Here a target group forwards TCP on port 5432 (a Postgres proxy) but probes health with a TCP connect.
# --- Python (boto3) ---import boto3elbv2 = boto3.client("elbv2", region_name="us-east-1")tg = elbv2.create_target_group( Name="db-proxy-tg", Protocol="TCP", Port=5432, VpcId="vpc-0abc", TargetType="ip", HealthCheckProtocol="TCP", # a connect is enough for a non-HTTP service HealthCheckIntervalSeconds=10,)tg_arn = tg["TargetGroups"][0]["TargetGroupArn"]listener = elbv2.create_listener( LoadBalancerArn=nlb_arn, Protocol="TCP", Port=5432, DefaultActions=[{"Type": "forward", "TargetGroupArn": tg_arn}],)
// --- TypeScript (AWS SDK v3) ---import { ElasticLoadBalancingV2Client, CreateTargetGroupCommand, CreateListenerCommand } from "@aws-sdk/client-elastic-load-balancing-v2";const elbv2 = new ElasticLoadBalancingV2Client({ region: "us-east-1" });const tg = await elbv2.send(new CreateTargetGroupCommand({ Name: "db-proxy-tg", Protocol: "TCP", Port: 5432, VpcId: "vpc-0abc", TargetType: "ip", HealthCheckProtocol: "TCP", // a connect is enough for a non-HTTP service HealthCheckIntervalSeconds: 10,}));const tgArn = tg.TargetGroups?.[0].TargetGroupArn;const listener = await elbv2.send(new CreateListenerCommand({ LoadBalancerArn: nlbArn, Protocol: "TCP", Port: 5432, DefaultActions: [{ Type: "forward", TargetGroupArn: tgArn }],}));
The listener Protocol is TCP; for a chat or telemetry service it would be UDP, and for a protocol that needs both (like some DNS setups) TCP_UDP. There are no routing rules - an NLB listener forwards straight to its target group by port.
Because an NLB operates at Layer 4 and does not terminate the connection, an instance or ip target sees the original client IP as the source address, with no X-Forwarded-For header needed. That is a real advantage for services that allowlist by IP, do geolocation, or log client addresses.
There is a catch worth knowing: with client IP preservation, a client cannot reach the NLB and also be a target behind it via the same connection (the hairpin/loopback case), and security groups on the targets must allow the client CIDR, not the NLB's address. Plan target security groups accordingly.
An ALB always spreads traffic evenly across all Availability Zones. An NLB does not - by default each NLB node only sends traffic to targets in its own AZ. If your target counts are uneven across AZs, load will be uneven too. Turn on cross-zone balancing with a target-group (or load-balancer) attribute.
Note the trade-off: cross-zone traffic on an NLB crosses AZ boundaries and can incur inter-AZ data transfer charges, unlike the ALB where cross-zone is free. Enable it for even distribution, keep it off to minimize cross-AZ cost when targets are already balanced.
The same waiter and health APIs apply. Wait for the NLB to be active, then confirm targets are healthy.
# --- Python (boto3) ---elbv2.get_waiter("load_balancer_available").wait(LoadBalancerArns=[nlb_arn])health = elbv2.describe_target_health(TargetGroupArn=tg_arn)print([d["TargetHealth"]["State"] for d in health["TargetHealthDescriptions"]])
Using Subnets when you need a fixed IP. Static and Elastic IPs come only from SubnetMappings. Plain Subnets gives AWS-assigned addresses that are stable but not chosen by you.
Forgetting cross-zone is off. Uneven target counts across AZs cause uneven load on an NLB unless you enable load_balancing.cross_zone.enabled.
Target security groups blocking the client. With source IP preservation, targets must allow the real client CIDR, not the NLB, or health checks and traffic fail.
Expecting routing rules. An NLB has none - one listener forwards to one target group by port. Content routing needs an ALB.
Cross-zone data-transfer cost. Enabling cross-zone on an NLB can add inter-AZ transfer charges; on an ALB it is free. Weigh evenness against cost.
Elastic IPs must exist first.AllocationId references an EIP you already allocated; allocate with EC2 AllocateAddress before CreateLoadBalancer.
Application Load Balancer whenever the traffic is HTTP/HTTPS and you want path/host routing, WAF, or per-request features - the L4 speed of NLB is wasted on it.
NLB in front of an ALB (TargetTypealb) to combine a static IP with Layer 7 routing when you need both.
Global Accelerator for anycast static IPs and cross-region traffic steering above one or more regional load balancers.
VPC Lattice or PrivateLink for service-to-service connectivity where a shared load balancer is the wrong abstraction.
Reach for an NLB when the workload is non-HTTP, latency-critical, or needs a fixed IP; use an ALB or the alternatives when you need HTTP routing, edge behavior, or cross-region reach.
Call CreateLoadBalancer with Type: "network". Use Subnets for AWS-assigned addresses or SubnetMappings when you need static or Elastic IPs.
How do I give an NLB a static IP?
Use SubnetMappings with an AllocationId (a pre-allocated Elastic IP) per subnet for a public NLB, or PrivateIPv4Address per subnet for an internal one.
Which protocols can an NLB listener use?
TCP, UDP, TCP_UDP, and TLS. It cannot use HTTP/HTTPS, which are ALB-only listener protocols.
Can an NLB health-check a non-HTTP service?
Yes. Set HealthCheckProtocol to TCP for a simple connect check, or use HTTP/HTTPS against a health endpoint if the service exposes one.
Does an NLB preserve the client's source IP?
Yes, by default for instance and ip targets. The backend sees the real client address, so target security groups must allow the client CIDR.
Is cross-zone load balancing on by default for an NLB?
No. Each NLB node serves only its own AZ's targets unless you set load_balancing.cross_zone.enabled to true, which may add inter-AZ transfer cost.
Does an NLB support path or host routing?
No. Those are Layer 7 ALB features. An NLB listener forwards by port to a single target group with no content-based rules.
Can an NLB terminate TLS?
Yes, with a TLS listener and an ACM certificate. It can also pass TLS through with a TCP listener so the target terminates it.
What target types does an NLB support?
instance, ip, and alb (an ALB as the target). lambda targets are an ALB feature, not an NLB one.
Do I allocate Elastic IPs before or after creating the NLB?
Before. Allocate them with EC2 AllocateAddress, then reference each AllocationId in the NLB's SubnetMappings.
Load Balancing Basics - the shared create/register/listen workflow, shown on an ALB.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+). 636f64656775696465732e696f7c6367696f313134347c323032363037
Revisado por Chris St. John·Última actualización: 23 jul 2026