Why ELB Is Split into 4 Types - Behind the Design Decisions of ALB / NLB / GWLB / CLB

This article explains why the 4 load balancer types, ALB, NLB, GWLB, and CLB (Classic), coexist instead of being unified, from the layers of the OSI reference model, their performance characteristics, and their history.

Classic Load Balancer - The Origin of ELB

Elastic Load Balancing (today's Classic Load Balancer), launched in 2009, was the original load balancer service of AWS. CLB was designed as a general-purpose load balancer that can handle both L4 (TCP) and L7 (HTTP/HTTPS) traffic. However, this "do-everything" design later created problems. L4 and L7 load balancing are technically fundamentally different kinds of processing. L4 routes by looking only at the source and destination IP addresses and port numbers of a packet. It does not parse the contents of the packet (HTTP headers or body) at all. L7 routes by parsing the content of the HTTP request (URL path, Host header, Cookie, and so on). Providing these 2 kinds of processing in 1 service creates a trade-off: the L7 overhead affects L4 processing, and L7 feature extensions affect L4 stability. Because of this constraint, CLB could not implement advanced L7 routing (path-based routing and host-based routing). AWS today positions CLB as intended for applications built on the EC2-Classic network and recommends migrating to ALB or NLB. That CLB belongs to an older generation also shows in its family of control APIs. CLB is operated through the original Elastic Load Balancing API (version 2012-06-01), while ALB, NLB, and GWLB, which were added later, belong to a separate API family built around target groups (elasticloadbalancingv2, version 2015-12-01).

The Birth of ALB - A Design Specialized for L7

Application Load Balancer (ALB), launched in 2016, is a load balancer fully specialized for L7 (HTTP/HTTPS). It made possible what was impossible with CLB: path-based routing (/api/* to the API servers, /static/* to the static file servers), host-based routing (api.example.com and www.example.com to different target groups), and routing based on HTTP headers or cookies. Important features that ALB achieved by specializing in L7 are native WebSocket support and HTTP/2 support. CLB could not handle WebSocket on HTTP/HTTPS listeners and needed a workaround that passed it through a TCP listener without parsing the contents. It does not support HTTP/2 either. ALB has also kept adding features closely tied to the application layer, such as integration with AWS WAF, built-in Cognito authentication, and the ability to invoke Lambda functions directly as targets. These features are possible precisely because the L7 HTTP request can be parsed, and they are impossible in principle for an L4 load balancer. The strength of being able to parse L7 also shows in support for new protocols. ALB target groups have a setting called protocol version, and besides the default HTTP/1.1 you can choose HTTP/2 or gRPC (according to the official documentation as of August 2026). When you choose gRPC, ALB parses gRPC requests, routes them to the appropriate target group per package, service, and method, and can handle all of unary, client streaming, server streaming, and bidirectional streaming. For health checks, you specify the method in the form /package.service/method and also decide yourself which gRPC status codes count as success. As constraints, the listener protocol is HTTPS only, the listener rule action is forward only, and the target type is instance or ip only, so Lambda functions cannot be targets. ALB pricing is calculated in its own unit called the LCU (Load Balancer Capacity Unit). The LCU is determined by the maximum of 4 metrics: new connections, active connections, processed bytes, and rule evaluations.

The Birth of NLB - Pursuing Extreme L4 Performance

Network Load Balancer (NLB), launched in 2017, is a load balancer specialized for L4 (TCP/UDP/TLS) that pursues extreme performance. NLB can handle millions of requests per second, and its latency is kept lower than that of ALB. However, AWS does not publish concrete latency figures for either, and its official wording for NLB stays at the qualitative "ultra-low latency". The right approach is to decide by measuring your own workload rather than by comparing catalog values. This performance difference comes from NLB not parsing packet contents at all. NLB decides routing per flow (the combination of source IP + port and destination IP + port) and forwards subsequent packets to the same target. Because there is no processing such as parsing HTTP headers, reading cookies, or evaluating URL paths, the number of processing stages a packet passes through is itself small, and the overhead stays low. One more important feature of NLB is support for static IP addresses. Because the IP addresses of ALB change dynamically, it can be reached only by its DNS name. NLB has a fixed IP address in each AZ (an Elastic IP can be assigned), so it can be registered in a firewall's IP allowlist. In environments that need fixed destination IP addresses, such as financial institutions and telecommunications carriers, NLB is mandatory. In addition, NLB can preserve the client's source IP all the way to the target, so the application can identify where access comes from without relying on forwarding headers.

The Addition of Gateway Load Balancer - A Fourth Option That Inserts Appliances into the Path

Gateway Load Balancer (GWLB), added in 2020, is the fourth load balancer. Whereas ALB and NLB are devices that "choose the destination of the traffic they receive", GWLB is a device that "inserts inspection devices into the path of the traffic", so its purpose points in a different direction to begin with. Its use is to bundle third-party virtual appliances, such as firewalls, intrusion detection and prevention systems (IDS/IPS), and deep packet inspection devices, behind a transparent, unified entry and exit point and scale them with demand. GWLB operates at layer 3 (the network layer) of the OSI reference model, listens for all IP packets on all ports, and forwards them to the target group specified in the listener rule. So that the same flow reaches the same appliance, it maintains flow stickiness with a 5-tuple by default (a 3-tuple or 2-tuple are also available). Between GWLB and the registered appliances, traffic is exchanged with the GENEVE (RFC 8926) protocol on port 6081 (according to the official documentation as of August 2026). Encapsulation is needed here not for the convenience of the appliances but because of the transparency requirement itself. Carrying the original packet without rewriting any of it is the premise of transparent operation, and because the unmodified packet's source and destination IPs do not match the IPs of GWLB or the appliances, ordinary IP-based VPC routing would bypass both GWLB and the appliances. There is no way to connect the two other than wrapping the original packet in a new L3 packet. Furthermore, because GENEVE carries arbitrary additional information in TLV (Type-Length-Value) format, GWLB can attach information such as the endpoint ID and the flow cookie to each packet. As a result, even multi-tenant appliances whose CIDRs can overlap can distinguish where traffic came from and avoid mixing up flows. AWS officially explains that it chose GENEVE because VXLAN and GRE, which have only fixed-length fields, did not meet this requirement. The deployment also takes a dedicated form. GWLB is placed in the same VPC as the virtual appliances, and the appliances are registered in a target group. To hand off traffic across the VPC boundary, a Gateway Load Balancer endpoint based on AWS PrivateLink is used. In the consumer VPC, the route table specifies this endpoint as the next hop, so the endpoint and the application servers must be created in separate subnets. Inspection can be inserted without changing the application's settings because this path design and the encapsulation work together.

Why Not Unify Into One Service

The question "Why not unify ALB and NLB into 1 service?" is a natural one, but the reasons for not unifying them are technically clear. L4 and L7 load balancing have fundamentally different processing pipelines. L7 receives all packets, reassembles them into an HTTP request, parses the headers, evaluates the routing rules, rewrites headers as needed, and then forwards to the target. This processing consumes memory and CPU. L4 decides the destination by looking only at the packet headers (IP + TCP/UDP) and does not touch the packet contents. If these 2 kinds of processing are unified into 1 service, L4 performance is dragged down by the L7 processing pipeline and degrades. Adding GWLB makes the reason they cannot be unified 1 step clearer. ALB and NLB are devices that themselves terminate connections or requests and rewrite headers or addresses as needed. GWLB, by contrast, is required by its specification not to rewrite the original packet, and for that purpose it has a data path premised on encapsulation and coordination with route tables. If a terminating device and a transparent device were combined into 1 product, the settings would mix items that are meaningless to each other, and users would lose sight of "which behavior it is performing right now". The fact that CLB, with its "do-everything" design, could not implement advanced L7 routing shows that this split is not an afterthought of convenience. AWS's design philosophy of "purpose-built services" is a policy of separating functions and optimizing each in order to avoid this kind of trade-off. The fact that there are 4 types is not a proliferation of options but the result of assigning an optimal implementation to each of 4 different jobs: terminating at L7, terminating at L4, transparently inserting at L3, and the older-generation general-purpose type.

Selection Criteria

Choosing among the 4 ELB types is determined by the characteristics of the workload. If you process HTTP/HTTPS traffic and need path-based or host-based routing, it is ALB. For most web applications, REST APIs, and microservices, ALB is the best fit, and for gRPC as well, ALB, which can handle it natively through the target group protocol version, is the first candidate. If you process TCP/UDP traffic and need extreme performance or static IPs, it is NLB. It suits workloads where L7 parsing is unnecessary and connection counts and latency dominate, such as game servers, connections from IoT devices, and financial trading systems. If you want to insert third-party firewalls, IDS/IPS, or deep packet inspection devices into the traffic path, it is GWLB. This is less a choice of load balancer than a design decision to consolidate the entry and exit points of the inspection platform in 1 place and scale the group of appliances. However, because GENEVE-compatible appliances and path design are prerequisites, you decide on adoption after checking the integration requirements in the official documentation. CLB is not chosen for new builds. AWS positions CLB as intended for applications on the EC2-Classic network (retired in 2022) and recommends migrating to ALB or NLB. For migration there is an official migration wizard, which can create an equivalent ALB or NLB from the settings of an existing CLB. However, the wizard only creates a new load balancer and does not convert the existing CLB, so you need to switch the traffic over yourself. There are also patterns that combine them. If you place ALB behind NLB, you can have both the static IPs of NLB and the L7 routing of ALB. NLB can be used for an AWS PrivateLink endpoint service, so this configuration is chosen when you publish a service through PrivateLink and also need L7 routing. GWLB is not exclusive with the other 3; the basic way to use it is to insert it into the routing path in front of ALB or NLB and use them together.

References (Official AWS Resources)

The primary sources for this page are the official AWS website and documentation. Check the official pages below for the latest specifications and pricing.

If this page and the official documentation disagree, treat the official documentation as authoritative.

Share