Blog

ALB vs NLB: Application Load Balancer vs Network Load Balancer on AWS

October 16, 2026 · Pushpjeet Cholkar

Last updated:

Short answer: Use an Application Load Balancer (ALB) for HTTP, HTTPS and gRPC when you need routing by host, path or header, AWS WAF, user authentication or Lambda targets. Use a Network Load Balancer (NLB) for TCP, UDP, TLS or QUIC traffic, static IP addresses, AWS PrivateLink, or TLS that must stay encrypted all the way to your targets.

ALB vs NLB at a glance

Application Load Balancer (ALB) Network Load Balancer (NLB)
OSI layer Layer 7 (application) Layer 4 (transport)
Listener protocols HTTP, HTTPS (HTTP/2 and gRPC over HTTPS) TCP, UDP, TCP_UDP, TLS, QUIC, TCP_QUIC
Routing Listener rules on host, path, HTTP headers, method, query string and source IP; redirects, fixed responses, weighted target groups Flow hash per connection; weighted target groups; on dual-stack NLBs, rules by source IP version (IPv4 or IPv6) only
Static IP / Elastic IP No; use the DNS name (or put an NLB or AWS Global Accelerator in front) Yes: one static IP per enabled AZ, optional Elastic IP per subnet (internet-facing)
Client IP at the target Load balancer’s IP on the packet; client IP in X-Forwarded-For Preserved for instance targets and for UDP/QUIC; off by default for ip targets on TCP/TLS (turn it on, or use proxy protocol v2)
Security groups Always used Optional, and only if attached at creation
Target types Instance, IP, Lambda Instance, IP, ALB
WebSockets Yes (HTTP/1.1 upgrade on HTTP and HTTPS listeners) Yes on TCP, TLS, TCP_UDP and TCP_QUIC listeners
TLS termination HTTPS listener; mutual TLS (verify or passthrough) TLS listener with optional ALPN; or TCP passthrough on 443; no mutual TLS at the load balancer
Health checks HTTP or HTTPS (gRPC status codes for gRPC targets) TCP (default), HTTP or HTTPS
Cross-zone default Always on at load balancer level; can be turned off per target group Off by default; turn on per load balancer or target group
Idle timeout 60 seconds by default (configurable) TCP: 350 seconds by default, configurable from 60 to 6,000
IPv6 IPv4, dual-stack, dual-stack without public IPv4 IPv4, dual-stack
Minimum zones Two Availability Zones One Availability Zone (more recommended)
Typical uses Websites, REST and gRPC APIs, microservices, containers, Lambda back ends Non-HTTP TCP/UDP services, gaming, IoT, PrivateLink services, fixed-IP allowlists, end-to-end TLS
Pricing model Hourly charge plus Load Balancer Capacity Units (LCUs) Hourly charge plus Network Load Balancer Capacity Units (NLCUs)

Features from AWS documentation, checked October 16, 2026. AWS adds load balancer features often, so confirm in the linked docs before you design around one.

What is an Application Load Balancer?

An Application Load Balancer works at the application layer, the seventh layer of the OSI model. It terminates the client’s connection, reads each HTTP request and evaluates your listener rules in priority order. Each rule has conditions (host header, path, HTTP header, method, query string or source IP) and an action: forward to a target group, redirect, or return a fixed response.

That makes ALB the natural front door for web applications and microservices. One ALB can serve api.example.com and www.example.com, send /images/* to one service and /api/* to another, and redirect HTTP to HTTPS.

Facts worth remembering:

What is a Network Load Balancer?

A Network Load Balancer works at the fourth layer of the OSI model and is designed to handle millions of requests per second. It doesn’t read HTTP. For TCP, it picks a target with a flow hash of the protocol, source and destination IP and port, and the TCP sequence number, then keeps that connection on the same target for its lifetime. UDP flows are hashed the same way without the sequence number.

Facts worth remembering:

How do ALB and NLB differ in practice?

Which OSI layer does each one work at, and why does it matter?

Layer 7 means the ALB sees URLs, headers and cookies, so it can make a decision per request. Layer 4 means the NLB sees IP addresses, ports and connections, so it makes a decision per connection or flow. If your rule needs the word “path”, “host” or “header”, you need an ALB. If your protocol isn’t HTTP, or you need the load balancer to stay out of the payload, you need an NLB.

Does the load balancer get a static IP address?

NLB does: one per enabled zone, optionally an Elastic IP you own. ALB does not offer static or Elastic IPs, and clients should always resolve its DNS name, because the addresses behind it change as it scales. If a partner insists on fixed IPs for an HTTP application, you have two documented options: register the ALB as a target of an NLB, or put AWS Global Accelerator in front, which provides two static anycast IPv4 addresses.

Will my application see the client’s IP address?

With an ALB, the TCP connection to your target comes from the load balancer, so server logs show the ALB’s private IP. The client address is in the X-Forwarded-For header, which ALB appends by default (you can set it to preserve or remove instead). Only trust that header when it was added by systems you control.

With an NLB, it depends on the target group:

Preserved client IPs change your security group design. Your targets now see client addresses, not the NLB’s, so the target security group must allow them. The cleanest fix is to give the NLB a security group and reference it in the target’s rules.

How do security groups work with ALB and NLB?

An ALB always has security groups. Their rules must allow traffic in both directions on the listener ports and the health check ports, so review them whenever you add a listener or change a health check port.

NLB support for security groups is newer, and it comes with one trap: you can only associate security groups when you create the NLB. If you create it without any, you can’t add them later; you would have to replace the load balancer. Once an NLB has security groups, you can change them at any time. Health checks are subject to the NLB’s outbound rules, and AWS doesn’t charge for traffic that the inbound rules block. The trade-off: QUIC and TCP_QUIC listeners aren’t allowed on an NLB that has security groups.

Where should TLS be terminated?

You have three patterns:

  1. Terminate on the ALB (HTTPS listener). The ALB decrypts, applies rules and WAF, and can re-encrypt to HTTPS targets. ALB also supports mutual TLS: in verify mode it checks client certificates against a trust store you upload; in passthrough mode it forwards the client certificate chain to your targets in HTTP headers.
  2. Terminate on the NLB (TLS listener). Good for non-HTTP protocols over TLS, or HTTP when you don’t need layer 7 features. You can set an ALPN policy such as HTTP2Preferred; the default is None. NLB does not support mutual TLS at the load balancer.
  3. Pass through (NLB TCP listener on 443). The NLB forwards encrypted bytes untouched and your targets hold the certificates. Use this when compliance says keys live only on your servers, or when targets must do mutual TLS themselves.

One practical detail: for both ALB and NLB, the console’s default security policy is ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09, but the AWS CLI, CloudFormation and the CDK default to the much older ELBSecurityPolicy-2016-08. Set --ssl-policy explicitly in scripts and templates.

How do cross-zone defaults differ?

With cross-zone load balancing on, each load balancer node spreads traffic across targets in all enabled zones. With it off, each node only uses targets in its own zone. ALB has it on at the load balancer level and lets you turn it off per target group. NLB has it off by default.

That default matters when your zones are uneven. With two zones, two targets in one and eight in the other, and cross-zone off, each of the two targets gets 25% of the traffic while each of the eight gets 6.25%. Turning cross-zone on evens it out to 10% each. On NLB, turning it on also means you pay regional data transfer for traffic that crosses zones, so the alternative is to keep it off and balance target counts per zone.

What about idle timeouts and long-lived connections?

ALB closes a connection that has been idle for 60 seconds by default (idle_timeout.timeout_seconds), and has a separate client keepalive duration of 3,600 seconds. If you run long requests or quiet WebSocket connections, raise the idle timeout or send keepalives.

NLB’s TCP idle timeout defaults to 350 seconds and is configurable per listener from 60 to 6,000 seconds (tcp.idle_timeout.seconds). Database connection pools and IoT clients that sit quiet for minutes are the classic reason to change it.

Both handle WebSockets. On ALB, once a connection upgrades to WebSocket, listener rules and AWS WAF no longer apply to it. On NLB, WebSockets work on TCP, TLS, TCP_UDP and TCP_QUIC listeners.

How do health checks differ?

ALB health checks are HTTP or HTTPS GET requests to a path you choose (default /), and a target is healthy when it returns a code you allow (200 by default, configurable from 200 to 499). For gRPC target groups you match gRPC status codes instead.

NLB defaults to a simple TCP health check and also supports HTTP and HTTPS. NLB health checks are distributed and use a consensus mechanism, so each target receives more checks than the interval suggests. Keep the HTTP health check endpoint cheap, such as a static page. If health checks fail and you can’t see why, test the port from inside the VPC with curl and ss; the Linux networking basics module walks through both.

How is each one priced?

This post doesn’t quote prices; they vary by Region and change. What matters for design is the model:

Check Elastic Load Balancing pricing and model your traffic in the AWS Pricing Calculator.

Which one should you use? A decision guide

Your situation Pick Why
Website or REST API with paths, hosts or subdomains ALB Listener rules route per request
gRPC services ALB gRPC protocol version on an HTTPS listener
HTTP API on AWS Lambda ALB Only ALB supports Lambda targets
Clients authenticate with certificates at the load balancer ALB with mutual TLS NLB has no mTLS at the load balancer
Game servers, VoIP, DNS or other UDP NLB ALB has no UDP listeners
HTTP/3 over QUIC handled by your own servers NLB (QUIC or TCP_QUIC) QUIC passthrough; no security groups on that NLB
Partner needs fixed IPs to allowlist NLB with Elastic IPs Static IP per zone
Fixed IPs and path or host routing NLB in front of ALB NLB gives the IPs, ALB the rules
Share a TCP service privately with other VPCs or accounts NLB behind a VPC endpoint service PrivateLink endpoint services use NLB
TLS must be decrypted only on your servers NLB, TCP listener on 443 Encrypted traffic passes through
Firewall or IDS appliances inspecting all traffic Gateway Load Balancer Layer 3, GENEVE to appliances

To make the first questions concrete, here is a small Python rule-of-thumb picker. It is a teaching aid, not a sizing tool.

"""Rule-of-thumb picker: Application Load Balancer or Network Load Balancer?

It encodes the first questions an architect asks about a workload. It is a
teaching aid, not a sizing tool: confirm features and quotas in the AWS docs.
Run: python3 pick_load_balancer.py
"""


def pick_load_balancer(protocol: str, *, static_ip: bool = False,
                       privatelink: bool = False, l7_routing: bool = False,
                       lambda_target: bool = False, client_cert_auth: bool = False,
                       targets_decrypt_tls: bool = False,
                       inline_appliance: bool = False) -> str:
    """Return a recommendation with a one-line reason.

    protocol            -- "http", "https", "grpc", "websocket", "tcp", "tls",
                           "udp" or "quic"
    static_ip           -- clients or partners must allowlist fixed IPs
    privatelink         -- expose the service to other VPCs as an endpoint service
    l7_routing          -- route by host, path, header, method or query string
    lambda_target       -- send requests to an AWS Lambda function
    client_cert_auth    -- the load balancer itself must verify client certificates
    targets_decrypt_tls -- TLS must stay end to end, decrypted only on the targets
    inline_appliance    -- inspect all traffic with firewall/IDS appliances
    """
    if inline_appliance:
        return "Gateway Load Balancer: layer 3 gateway for GENEVE appliances"
    if protocol in ("udp", "quic"):
        return "NLB: UDP and QUIC listeners (ALB listens on HTTP/HTTPS only)"
    if targets_decrypt_tls:
        return "NLB with a TCP listener on 443: encrypted bytes pass through untouched"
    web = protocol in ("http", "https", "grpc", "websocket")
    if web and (static_ip or privatelink):
        if l7_routing or lambda_target or client_cert_auth:
            return ("NLB in front of ALB (target type alb): static IPs or "
                    "PrivateLink from NLB, HTTP routing from ALB")
        return "NLB: static IP per AZ and PrivateLink; HTTP stays opaque to it"
    if lambda_target:
        return "ALB: the only load balancer with Lambda targets"
    if client_cert_auth:
        return "ALB with mutual TLS (verify mode): NLB does not support mTLS"
    if protocol == "grpc":
        return "ALB: HTTPS listener plus gRPC protocol version on the target group"
    if web:
        return "ALB: layer 7 rules, redirects, WAF and X-Forwarded-For"
    if protocol in ("tcp", "tls"):
        if privatelink:
            return "NLB: a PrivateLink endpoint service is fronted by an NLB"
        return "NLB: layer 4 TCP/TLS with flow hash routing"
    raise ValueError(f"unknown protocol: {protocol}")


scenarios = [
    ("Public website: /api to containers, /images to another service",
     dict(protocol="https", l7_routing=True)),
    ("gRPC microservices behind one HTTPS endpoint", dict(protocol="grpc")),
    ("Multiplayer game server on UDP 7777", dict(protocol="udp")),
    ("Partner must allowlist fixed IPs; API uses host-based routing",
     dict(protocol="https", static_ip=True, l7_routing=True)),
    ("SaaS database proxy shared with customer VPCs over PrivateLink",
     dict(protocol="tcp", privatelink=True)),
    ("Payments service: TLS must be decrypted only on the targets",
     dict(protocol="tls", targets_decrypt_tls=True)),
    ("Serverless HTTP API on Lambda", dict(protocol="https", lambda_target=True)),
    ("IoT devices authenticate with client certificates over HTTPS",
     dict(protocol="https", client_cert_auth=True)),
    ("Inline firewall fleet for all VPC egress", dict(protocol="tcp", inline_appliance=True)),
]
for name, kwargs in scenarios:
    print(f"{name}\n  -> {pick_load_balancer(**kwargs)}")

Output (Python 3.13.5, run on October 16, 2026):

Public website: /api to containers, /images to another service
  -> ALB: layer 7 rules, redirects, WAF and X-Forwarded-For
gRPC microservices behind one HTTPS endpoint
  -> ALB: HTTPS listener plus gRPC protocol version on the target group
Multiplayer game server on UDP 7777
  -> NLB: UDP and QUIC listeners (ALB listens on HTTP/HTTPS only)
Partner must allowlist fixed IPs; API uses host-based routing
  -> NLB in front of ALB (target type alb): static IPs or PrivateLink from NLB, HTTP routing from ALB
SaaS database proxy shared with customer VPCs over PrivateLink
  -> NLB: a PrivateLink endpoint service is fronted by an NLB
Payments service: TLS must be decrypted only on the targets
  -> NLB with a TCP listener on 443: encrypted bytes pass through untouched
Serverless HTTP API on Lambda
  -> ALB: the only load balancer with Lambda targets
IoT devices authenticate with client certificates over HTTPS
  -> ALB with mutual TLS (verify mode): NLB does not support mTLS
Inline firewall fleet for all VPC egress
  -> Gateway Load Balancer: layer 3 gateway for GENEVE appliances

Notice the order of the checks. Appliance and protocol questions come first, because they rule one option out entirely. Fixed IPs and PrivateLink come next, because they force an NLB even for HTTP traffic. Only then do the layer 7 features decide between NLB alone and NLB in front of ALB.

Choosing a load balancer is a common theme in AWS Solutions Architect Associate exam scenarios. Watch for the clue words: “static IP”, “UDP”, “path-based”, “PrivateLink”, “client certificate”, “Lambda”. The AWS Solutions Architect course practices these scenarios in labs.

Can you put an NLB in front of an ALB?

Yes, and it is the standard answer when you need both worlds. You create a target group of type alb with protocol TCP, register the ALB, and point an NLB TCP listener at it. The NLB provides static IPs and PrivateLink; the ALB keeps its layer 7 rules, WAF and certificates.

Know the constraints before you design around it:

Example architectures

1. A public web application. Route 53 points www.example.com to an internet-facing ALB in two zones. Rules send /api/* to ECS tasks registered by IP and everything else to the web tier. In the S3 vs EBS vs EFS three-tier example, this ALB is what sits in front of the Auto Scaling group.

Clients --HTTPS--> ALB (2+ AZs, WAF, HTTPS listener)
                    |-- /api/*  --> target group: ECS tasks (ip)
                    '-- default --> target group: EC2 Auto Scaling group (instance)

2. A non-HTTP service with fixed IPs. An internet-facing NLB with an Elastic IP per zone and a TLS listener in front of an MQTT broker or a custom TCP protocol. The NLB has a security group, and the targets’ security group allows traffic only from that group.

Devices --TLS:8883--> NLB (Elastic IP per AZ, TLS listener, security group)
                       '--> target group: brokers (instance, client IP preserved)

3. A SaaS API that customers reach privately. An internal NLB forwards TCP 443 to an internal ALB (target type alb). A VPC endpoint service on the NLB lets customer VPCs connect through PrivateLink, while the ALB does host-based routing per tenant.

Customer VPC --PrivateLink--> NLB (TCP 443) --> ALB (HTTPS rules) --> services

Hands-on: illustrative AWS CLI commands

Create an ALB with an HTTPS listener and a path rule

aws elbv2 create-load-balancer --name web-alb --type application \
  --scheme internet-facing --ip-address-type dualstack \
  --subnets subnet-0aaa1111bbbb2222c subnet-0ddd3333eeee4444f \
  --security-groups sg-0alb1234567890abc

aws elbv2 create-target-group --name web-api-tg --protocol HTTP --port 8080 \
  --vpc-id vpc-0123456789abcdef0 --target-type ip \
  --health-check-path /healthz --matcher HttpCode=200

aws elbv2 create-listener --load-balancer-arn <alb-arn> \
  --protocol HTTPS --port 443 \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09 \
  --certificates CertificateArn=<acm-certificate-arn> \
  --default-actions Type=forward,TargetGroupArn=<web-api-tg-arn>

aws elbv2 create-rule --listener-arn <https-listener-arn> --priority 10 \
  --conditions Field=path-pattern,Values='/images/*' \
  --actions Type=forward,TargetGroupArn=<images-tg-arn>

# Allow longer idle connections (default is 60 seconds)
aws elbv2 modify-load-balancer-attributes --load-balancer-arn <alb-arn> \
  --attributes Key=idle_timeout.timeout_seconds,Value=120

Note --subnets with two zones: an ALB needs at least two. dualstack also needs subnets with IPv6 ranges. And note the explicit --ssl-policy; leave it out and the CLI uses ELBSecurityPolicy-2016-08.

Create an NLB with Elastic IPs, a security group and a TLS listener

aws elbv2 create-load-balancer --name tcp-nlb --type network --scheme internet-facing \
  --subnet-mappings SubnetId=subnet-0aaa1111bbbb2222c,AllocationId=eipalloc-0a1b2c3d4e5f60001 \
                    SubnetId=subnet-0ddd3333eeee4444f,AllocationId=eipalloc-0a1b2c3d4e5f60002 \
  --security-groups sg-0nlb1234567890abc

aws elbv2 create-target-group --name tcp-app-tg --protocol TCP --port 9000 \
  --vpc-id vpc-0123456789abcdef0 --target-type instance --health-check-protocol TCP

aws elbv2 create-listener --load-balancer-arn <nlb-arn> \
  --protocol TLS --port 443 \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09 --alpn-policy HTTP2Preferred \
  --certificates CertificateArn=<acm-certificate-arn> \
  --default-actions Type=forward,TargetGroupArn=<tcp-app-tg-arn>

# Optional: spread traffic across zones (off by default on NLB; adds cross-zone data transfer)
aws elbv2 modify-load-balancer-attributes --load-balancer-arn <nlb-arn> \
  --attributes Key=load_balancing.cross_zone.enabled,Value=true

# Keep client IPs and shorten draining for faster deployments
aws elbv2 modify-target-group-attributes --target-group-arn <tcp-app-tg-arn> \
  --attributes Key=preserve_client_ip.enabled,Value=true Key=deregistration_delay.timeout_seconds,Value=60

# Raise the TCP idle timeout from the 350-second default
aws elbv2 modify-listener-attributes --listener-arn <tls-listener-arn> \
  --attributes Key=tcp.idle_timeout.seconds,Value=900

The --security-groups flag on create is the one you can’t add later. Even if you don’t need rules today, attaching a security group at creation keeps your options open (unless you plan QUIC listeners, which require an NLB without security groups).

Put the ALB behind the NLB

aws elbv2 create-target-group --name alb-behind-nlb --protocol TCP --port 443 \
  --target-type alb --vpc-id vpc-0123456789abcdef0 \
  --health-check-protocol HTTPS --health-check-path /healthz

aws elbv2 register-targets --target-group-arn <alb-behind-nlb-arn> \
  --targets Id=<alb-arn>,Port=443

aws elbv2 create-listener --load-balancer-arn <nlb-arn> --protocol TCP --port 443 \
  --default-actions Type=forward,TargetGroupArn=<alb-behind-nlb-arn>

In this layout the NLB listener on 443 is TCP, not TLS: the ALB still terminates HTTPS with its own certificate. (Use a different port, or a second NLB, if the same NLB already has the TLS listener from the previous step on 443.)

Check target health (illustrative output, trimmed):

aws elbv2 describe-target-health --target-group-arn <web-api-tg-arn>
{
    "TargetHealthDescriptions": [
        {
            "Target": { "Id": "10.0.1.25", "Port": 8080, "AvailabilityZone": "us-east-1a" },
            "HealthCheckPort": "8080",
            "TargetHealth": { "State": "healthy" }
        },
        {
            "Target": { "Id": "10.0.2.41", "Port": 8080, "AvailabilityZone": "us-east-1b" },
            "HealthCheckPort": "8080",
            "TargetHealth": { "State": "unhealthy", "Reason": "Target.ResponseCodeMismatch",
                              "Description": "Health checks failed with these codes: [404]" }
        }
    ]
}

A 404 like this usually means the health check path doesn’t exist on that target, not that the network is broken.

Clean up

aws elbv2 delete-load-balancer --load-balancer-arn <nlb-arn>        # also deletes its listeners
aws elbv2 deregister-targets --target-group-arn <alb-behind-nlb-arn> --targets Id=<alb-arn>
aws elbv2 delete-load-balancer --load-balancer-arn <alb-arn>
aws elbv2 delete-target-group --target-group-arn <target-group-arn>  # repeat for each target group
aws ec2 release-address --allocation-id eipalloc-0a1b2c3d4e5f60001   # repeat for each Elastic IP

Deleting a load balancer deletes its listeners but not its targets: instances keep running and stay registered with their target groups. An ALB can’t be deleted while it is registered with an NLB target group, which is why the deregister step comes first. Release the Elastic IPs you allocated for the NLB once you no longer need them.

Where do Gateway Load Balancer and Classic Load Balancer fit?

Gateway Load Balancer is not an ALB or NLB alternative for applications. It works at layer 3, listens for all IP packets on all ports, and sends them to virtual appliances (firewalls, intrusion detection, deep packet inspection) using GENEVE on port 6081. You reach it through Gateway Load Balancer endpoints in your route tables. Pick it when the requirement is “inspect everything”, not “serve my app”.

Classic Load Balancer is the previous generation. AWS recommends migrating to a current-generation load balancer, which for HTTP workloads usually means ALB and for TCP/SSL workloads usually means NLB. Don’t start new designs on it.

Common mistakes with ALB and NLB

  1. Creating an NLB without a security group. You can’t add one later. Attach one at creation unless you need QUIC.
  2. Hard-coding ALB IP addresses. They change. Use the DNS name, an alias record, or put an NLB or Global Accelerator in front for fixed IPs.
  3. Locking out NLB clients after turning on client IP preservation. Targets now see client IPs. Reference the NLB’s security group in the target security group, or allow the client ranges.
  4. Expecting path routing, WAF or redirects on an NLB. Those are layer 7 features. Use an ALB, or an NLB in front of an ALB.
  5. Forgetting NLB cross-zone is off. Uneven targets per zone means uneven load per target. Either balance the zones or turn cross-zone on and accept the data transfer cost.
  6. Leaving the default TLS policy in scripts. CLI and IaC default to ELBSecurityPolicy-2016-08. Set the policy you want explicitly.
  7. Planning mutual TLS on an NLB TLS listener. It isn’t supported. Use ALB mutual TLS, or a TCP listener with mTLS on the targets.
  8. Trusting every X-Forwarded-For value. Clients can send their own. Use the entries added by your load balancer.

Frequently asked questions

What is the main difference between ALB and NLB?

An Application Load Balancer works at layer 7 and routes each HTTP, HTTPS or gRPC request by host, path, headers or other request details. A Network Load Balancer works at layer 4 and forwards TCP, UDP, TLS or QUIC connections without reading the payload, and it offers a static IP per Availability Zone.

Does an Application Load Balancer have a static IP address?

No. ALB doesn’t support static or Elastic IP addresses, so clients should use its DNS name. If you need fixed IPs in front of HTTP routing, register the ALB as a target of a Network Load Balancer, or put AWS Global Accelerator in front of it.

Can a Network Load Balancer terminate TLS?

Yes. A TLS listener on an NLB terminates TLS with a server certificate and can negotiate HTTP/2 through an ALPN policy. NLB does not support mutual TLS at the load balancer. For mTLS, use an ALB, or use an NLB TCP listener and handle mTLS on the targets.

Do Network Load Balancers support security groups?

Yes, but only if you associate at least one security group when you create the NLB. You can’t add security groups later to an NLB that was created without them. QUIC and TCP_QUIC listeners are not allowed on an NLB that has security groups.

Can I put an ALB behind an NLB?

Yes. Create a target group of type alb with the TCP protocol, register the ALB, and forward an NLB TCP listener to it. Both load balancers must be in the same VPC and account. You get NLB static IPs or PrivateLink in front of ALB layer 7 routing.

Is NLB cheaper than ALB?

It depends on your traffic. Both charge per hour plus capacity units: LCUs for ALB, measured on connections, processed bytes and rule evaluations, and NLCUs for NLB, measured on connections or flows and processed bytes. TLS listeners on NLB use capacity faster than TCP. Model your numbers in the AWS Pricing Calculator.

Sources

All checked on October 16, 2026.


Learn AWS networking with guided practice. For live, instructor-led AWS classes with hands-on labs on load balancing, VPCs and architecture, see AWS training. If you are in the United States, see online AWS and AI/ML training in the USA. For more comparisons and labs, browse the AWS tutorials hub.

Newsletter

Enjoyed this post?

Get new posts, AI/ML tutorials, AWS batch dates and Oracle tips by email. No spam, unsubscribe anytime.

I’m interested in

Double opt-in: you’ll get a confirmation email first. Privacy policy

WhatsApp