The three services sit at different layers, accept different protocols, and a handful of the choices you make when you create them cannot be changed afterwards. This is what each one is actually for, where the protocol list makes the decision for you, the two cases where the right answer is a pair of them working together, and the settings that mean rebuilding rather than editing if you get them wrong.
Getting this one wrong is not a configuration mistake you fix on a Friday afternoon. The three services sit at different layers, accept different protocols, and several of the choices you make at creation time cannot be changed afterwards. Here is what each is for, where the protocol list decides for you, and which settings deserve a second look before you commit.
What each one is actually for
An Application Load Balancer functions at the application layer, the seventh layer of the OSI model. It reads the request, and it can route on the URL path, the host header, other HTTP headers, the method, query parameters and the source IP. Listener protocols are HTTP and HTTPS, on ports 1 to 65535. That is the entire list. If your traffic is not HTTP, an ALB cannot carry it.
A Network Load Balancer functions at the fourth layer. It does not read your request, it forwards a flow. Listener protocols are TCP, TLS, UDP, TCP_UDP, QUIC and TCP_QUIC. Elastic Load Balancing creates a network interface in each Availability Zone you enable, and each load balancer node uses that interface to get a static IP address. On an internet-facing NLB you can associate one Elastic IP address per subnet, which is the reason most teams reach for it, a fixed address a customer can put in their firewall.
CloudFront is a content delivery network and it serves content over HTTP or HTTPS. Origins can be an S3 bucket, an Elastic Load Balancing load balancer, a media service channel or any HTTP server, in any combination of up to 25 origins on a single distribution. By default each file stays in an edge location for 24 hours before it expires.
Where the protocol list decides it for you
Most of the time you do not choose. The protocol chooses.
WebSockets is the case people get wrong most often. An ALB provides native WebSocket support by upgrading an existing HTTP/1.1 connection, and you can use it on both HTTP and HTTPS listeners. On an NLB, WebSockets is supported only on TCP, TLS, TCP_UDP and TCP_QUIC listeners. CloudFront enables WebSocket functionality automatically on any distribution, but only over HTTP/1.1, and the cache behaviour has to forward the Sec-WebSocket-Key and Sec-WebSocket-Version headers to your origin, either by naming them in an origin request policy or by using the AllViewer managed policy.
HTTP/2 on an ALB works on HTTPS listeners, carrying up to 128 requests in parallel on one connection, and the HTTP/2 server push feature is not available. On CloudFront, HTTP/2 requires viewers to support TLS 1.2 or later and SNI, and HTTP/3 requires TLS 1.3 and SNI.
Mutual TLS splits them cleanly. An ALB supports mutual TLS authentication, including with HTTP/2, in both passthrough and verify modes. Network Load Balancers do not support it on a TLS listener, and the documented workaround is a TCP listener instead so the load balancer passes the connection through and your target implements mTLS itself.
Anything that is not HTTP, so a game protocol over UDP, a database wire protocol, SMTP, or media over RTP, has only one possible answer of the three.
When the answer is two of them
CloudFront in front of an ALB is the common pair. The distribution terminates TLS at the edge, absorbs the cacheable traffic and forwards the rest to the ALB as its origin, so you keep path-based routing and gain edge caching and a place to attach a web ACL.
The less obvious pair is an ALB registered as a target of an NLB. You create a target group of type alb, register a single Application Load Balancer in it, and point a TCP listener at that target group. AWS gives two reasons for doing this. You get the layer 7 request-based routing of the ALB combined with features the NLB supports, such as PrivateLink endpoint services and static IP addresses. It also serves applications that need one endpoint for multiple protocols, for example media services using HTTP for signalling and RTP to stream content.
Read the constraints before committing to it. Only one Application Load Balancer per target group, both load balancers in the same VPC within the same account, and an ALB can be a target of at most two Network Load Balancers using a separate target group for each. Only a TCP listener can forward to it. When the target group type is alb you cannot modify the target group attributes at all, and they always use their default values.
aws elbv2 create-target-group \
--name alb-behind-nlb \
--protocol TCP \
--port 443 \
--target-type alb \
--vpc-id vpc-0123456789abcdef0
The decisions that are hard to reverse
A few settings are chosen once and only changed by rebuilding.
A target group's target type cannot be changed after the target group is created. If you build instance target groups and later want to register IP addresses, or want to put the ALB behind an NLB, you create new target groups and move the listener across.
Security groups on a Network Load Balancer are the sharp one. If you do not associate any security groups with the NLB when you create it, you cannot associate them later. The inverse is also worth knowing at design time, because to use a QUIC or TCP_QUIC listener the Network Load Balancer must have no security groups.
A certificate used to require HTTPS between viewers and CloudFront has to be requested or imported in the US East (N. Virginia) Region, us-east-1, whatever Region everything else lives in. A certificate for the connection between CloudFront and an Elastic Load Balancing origin can be requested in any Region.
Removing a subnet from a live NLB is disruptive rather than irreversible, but it catches people. When a subnet is removed its network interface is deleted, which terminates all active connections in that Availability Zone, and every target in that zone is marked unused, including connections arriving from other zones through cross-zone load balancing.
The most expensive decision is not an AWS setting at all. It is the hostname you hand out to clients. Put your own domain in front of whichever of these you pick, with a short TTL, and you keep the ability to change your mind later.
Deciding in one pass
If the traffic is HTTP and you need to route on its content, that is an ALB. If it is not HTTP, or a third party needs to allowlist a fixed IP address, or you are publishing the service through PrivateLink, that is an NLB. If the traffic is global, largely cacheable, or you want TLS terminated closer to your users, put CloudFront in front of whichever one you already chose.
Where the answer is genuinely unclear, it is worth settling in architecture and planning rather than in production, and running the result afterwards is ordinary AWS cloud management.
Frequently asked questions
Should I use an ALB, an NLB or CloudFront for my traffic?
HTTP traffic that needs routing on its content belongs on an Application Load Balancer. Traffic that is not HTTP, needs a fixed IP address a third party can allowlist, or is published through PrivateLink belongs on a Network Load Balancer. CloudFront goes in front of whichever load balancer was chosen when the traffic is global, largely cacheable, or should have TLS terminated closer to users.
Which AWS load balancer can have a static IP address?
The Network Load Balancer. Each NLB node gets a static IP address from the network interface Elastic Load Balancing creates in every enabled Availability Zone, and an internet-facing NLB can take one Elastic IP address per subnet, a fixed address a customer can put in a firewall. NLB listeners accept TCP, TLS, UDP, TCP_UDP, QUIC and TCP_QUIC, while an Application Load Balancer listens only on HTTP and HTTPS.
Do ALB, NLB and CloudFront support WebSockets?
All three do, under different conditions. An ALB upgrades an existing HTTP/1.1 connection on both HTTP and HTTPS listeners, and an NLB supports WebSockets only on TCP, TLS, TCP_UDP and TCP_QUIC listeners. CloudFront enables WebSockets automatically over HTTP/1.1 only, and the cache behaviour must forward the Sec-WebSocket-Key and Sec-WebSocket-Version headers, either through an origin request policy or the AllViewer managed policy.
Does an AWS Network Load Balancer support mutual TLS?
No. Network Load Balancers do not support mutual TLS on a TLS listener. The documented workaround is a TCP listener, so the load balancer passes the connection through and the target implements mTLS itself. An Application Load Balancer does support mutual TLS authentication, including with HTTP/2, in both passthrough and verify modes.
Why put an Application Load Balancer behind a Network Load Balancer?
Registering an ALB as a target of an NLB combines the ALB's layer 7 request routing with NLB features such as PrivateLink endpoint services and static IP addresses. The pairing also gives one endpoint for multiple protocols, for example HTTP signalling with RTP streaming. The target group must be of type alb, hold a single ALB and sit behind a TCP listener, with both load balancers in the same VPC and account. An ALB can be a target of at most two NLBs.
Which ALB and NLB settings cannot be changed after creation?
A target group's target type is fixed at creation, so moving from instance targets to IP addresses, or putting an ALB behind an NLB, means new target groups and moving the listener across. A Network Load Balancer created with no security groups can never have them associated later. QUIC and TCP_QUIC listeners, in turn, require an NLB with no security groups, so the security group decision belongs at design time.
Which Region does a CloudFront viewer certificate have to be in?
A certificate used to require HTTPS between viewers and CloudFront has to be requested or imported in US East (N. Virginia), us-east-1, whatever Region everything else lives in. A certificate for the connection between CloudFront and an Elastic Load Balancing origin can be requested in any Region.
What does CloudFront add in front of an Application Load Balancer?
CloudFront in front of an ALB is the common pairing. The distribution terminates TLS at the edge, absorbs the cacheable traffic and forwards the rest to the ALB as its origin, so path-based routing stays and the setup gains edge caching and a place to attach a web ACL. By default CloudFront keeps each file in an edge location for 24 hours before it expires, and one distribution can use up to 25 origins.
Read how we handle it in Infrastructure Setup.
Related Articles
Upgrade RDS MySQL 8.0 to 8.4 With a Blue/Green Switch
RDS for MySQL 8.0 left standard support on July 31, 2026, and instances still on it are now billed for Extended Support. This shows how to reach 8.4 with a blue/green switch: what rules the method out, what 8.4 refuses that 8.0 accepted, the CLI steps, and why there is no switch-back unless you build one first.
CloudInfrastructure as Code: Terraform vs Pulumi
Compare Terraform and Pulumi for infrastructure as code with real-world examples, state management, testing strategies, and migration considerations.
CloudAWS Cost Optimization: 10 Things You're Probably Overpaying For
Ten common areas where AWS customers overspend, with practical strategies for right-sizing, reserved capacity, storage lifecycle management, and more.