All writing

ALB vs NLB: choose the network layer before the AWS product

Application Load Balancer and Network Load Balancer solve different forwarding problems. Choosing between them begins with HTTP semantics, connection behaviour, TLS ownership, client identity, static addressing and private connectivity, not a product feature checklist.

about 28 minutes min read

Suppose bfstore, the fictional organisation used throughout this series, is choosing an application entry point.

The request arrives on port 443.

That does not tell me whether bfstore needs an Application Load Balancer or a Network Load Balancer.

Both can accept encrypted traffic, distribute traffic across Availability Zones and operate as internet-facing or internal services.

The meaningful question is:

What information must the load balancer
understand before it chooses a target?

If the answer is:

hostname
URL path
HTTP method or header
query string
gRPC service and method
arbitrary source CIDR

the decision belongs at the application layer.

That points towards an Application Load Balancer.

If the answer is:

destination port
transport protocol
connection or flow
source IP preservation
source IP family
static endpoint address

the decision belongs at the transport layer.

That points towards a Network Load Balancer.

ALB operates at Layer 7 for HTTP and HTTPS. NLB operates at Layer 4 for protocols including TCP, TLS, UDP and QUIC.

ALB and NLB are not two performance tiers of the same product. They observe different parts of the traffic and therefore make different kinds of decisions.

Begin with the traffic contract.

The AWS product name comes later.

Begin with the forwarding question

Imagine requests arriving for two bfstore endpoints:

https://shop.bfstore.example/products/42

https://shop.bfstore.example/checkout

The traffic uses:

TCP
TLS
HTTP

Several layers are present at the same time.

APPLICATION

HTTP request
host
path
method
headers
gRPC metadata
        │
        ▼
TRANSPORT

TCP or UDP connection
source and destination ports
        │
        ▼
NETWORK

IPv4 or IPv6 packet
source and destination addresses

The correct load balancer depends on the layer at which bfstore needs to make the forwarding decision.

Suppose both requests should reach the same gateway.

shop.bfstore.example
        │
        ▼
one Envoy Gateway entry point

The load balancer may need only to establish a reliable connection to that gateway.

Suppose instead the load balancer itself should route:

/products/*  → catalog frontend

/checkout/*  → checkout frontend

/admin/*     → administration service

It must understand HTTP paths.

That is Layer 7 work.

A useful first question is therefore:

Does the load balancer need
to understand the request,
or merely forward the connection?

This question is more durable than:

Which AWS load balancer
is normally used for web traffic?

The first reveals the architecture.

The second invites cargo-cult infrastructure.

ALB is an HTTP-aware reverse proxy

An Application Load Balancer terminates the client-side HTTP or HTTPS connection and establishes a separate connection to a selected target.

It understands the HTTP request sufficiently to evaluate listener rules and perform application-level actions.

ALB listeners support HTTP and HTTPS. Rules can evaluate host names, paths, HTTP methods, headers, query strings and source IP conditions. They can forward, redirect, return fixed responses, authenticate users and transform host headers or URLs.

Conceptually:

CLIENT
  │
  │ HTTPS request
  ▼
APPLICATION LOAD BALANCER
  │
  ├── inspect host
  ├── inspect path
  ├── inspect method
  ├── inspect headers
  ├── authenticate where configured
  └── choose target group
          │
          ▼
       TARGET

This allows one ALB to act as an HTTP routing boundary for several applications.

api.bfstore.example
        │
        ├── /catalog/*  → catalog target group
        ├── /basket/*   → basket target group
        └── /orders/*   → order target group

Or several host names can share one listener:

shop.bfstore.example     → storefront

admin.bfstore.example    → administration

docs.bfstore.example     → documentation

The ALB is not merely splitting TCP connections between servers.

It is interpreting application protocol information before deciding what to do.

NLB is a connection and flow forwarder

A Network Load Balancer operates lower in the stack.

It accepts connections or flows and forwards them without becoming an HTTP-aware reverse proxy.

Current listener protocols include:

TCP

TLS

UDP

TCP_UDP

QUIC

TCP_QUIC

Since July 2026, an NLB listener can also choose target groups using the source IP address family:

IPv4 source → target group A

IPv6 source → target group B

A rule can forward new connections across weighted target groups. Existing connections continue on their original path when the weights change.

Conceptually:

CLIENT
  │
  │ TCP, UDP or QUIC traffic
  ▼
NETWORK LOAD BALANCER
  │
  ├── identify listener
  ├── evaluate source-family rule
  │   or default action
  ├── choose target group
  ├── choose target
  └── forward connection or flow
          │
          ▼
       TARGET

This remains transport-level routing.

The NLB does not inspect an HTTP host, path, method or header. It does not treat arbitrary source CIDRs as application-routing conditions.

It can forward a connection while remaining indifferent to a payload such as:

GET /products/42 HTTP/1.1

That makes NLB suitable when:

  • the application does not use HTTP
  • the application must receive raw TCP or UDP
  • TLS must pass through to the target
  • static zonal addresses are required
  • source-address preservation matters
  • IPv4 and IPv6 clients need different target groups
  • an AWS PrivateLink endpoint service is required
  • connection and flow behaviour is central to the design

NLB is not the simpler ALB.

It is solving a different forwarding problem.

QUIC is supported with constraints

NLB can pass through QUIC v1 traffic, including a combined TCP_QUIC listener for TCP and QUIC on the same port.

That support has important constraints:

  • the NLB must use the IPv4 address type
  • it cannot be dual-stack
  • it cannot have security groups attached
  • only one QUIC or TCP_QUIC listener may exist on the NLB
  • QUIC target groups cannot use IPv6
  • each registered QUIC target requires a unique eight-byte server ID

QUIC support is therefore a specific transport design, not a box to tick casually after the NLB has already been created.

HTTP traffic does not automatically require ALB

HTTP normally runs over TCP.

A Network Load Balancer can therefore forward an HTTP or HTTPS connection without understanding the HTTP messages inside it.

CLIENT
  │
  │ HTTPS
  ▼
NLB
  │
  │ encrypted TCP forwarded unchanged
  ▼
ENVOY OR APPLICATION
  │
  ├── terminate TLS
  ├── inspect HTTP
  └── route request

This may be appropriate when the downstream gateway must own:

  • TLS negotiation
  • client-certificate validation
  • HTTP routing
  • application retries
  • request transformation
  • protocol-specific telemetry

The NLB is providing transport-level entry.

The gateway behind it is providing application-level behaviour.

An ALB becomes useful when AWS should own some of that application-layer boundary.

CLIENT
  │
  │ HTTPS
  ▼
ALB
  │
  ├── terminate TLS
  ├── inspect HTTP
  ├── apply AWS WAF
  ├── route request
  └── forward to gateway or service

Both designs can carry HTTP.

The distinction is where the HTTP intelligence belongs.

Choose who owns TLS and client identity

Both ALB and NLB can terminate TLS, but they create different connections and expose client identity differently.

ALB HTTPS termination

An ALB HTTPS listener presents a certificate, negotiates TLS and decrypts the request.

It can then inspect HTTP, apply listener rules, authenticate users, verify configured JWTs, perform mutual TLS, apply AWS WAF and forward using HTTP or HTTPS.

CLIENT
  │ TLS connection A
  ▼
ALB
  │ optional TLS connection B
  ▼
TARGET

The target sees the ALB as its network peer. The original client address is carried as HTTP metadata, normally in X-Forwarded-For.

The application should trust forwarded identity only when the request arrived through the approved proxy chain, direct target access is prevented and the complete forwarded chain is parsed correctly.

NLB TLS termination

An NLB TLS listener can also present a certificate and terminate the client connection.

CLIENT
  │ TLS connection A
  ▼
NLB
  │ TCP or TLS connection B
  ▼
TARGET

The NLB still does not become an HTTP router.

A TLS target group encrypts the backend connection, but NLB does not validate the target certificate. Encryption and authenticated backend identity are separate requirements.

NLB TLS listeners also do not perform mutual TLS authentication.

Target-owned TLS and mutual TLS

When the target must receive the original encrypted stream, use an NLB TCP listener.

CLIENT
  │ original TLS or mTLS session
  ▼
NLB TCP LISTENER
  │ encrypted TCP unchanged
  ▼
TARGET TERMINATES TLS

This is the model when the target must possess the private key, perform the original handshake or validate the client certificate itself.

NLB source-address preservation

NLB can preserve the original client IP when the target and path support it.

DIRECT SUPPORTED PATH

client → NLB → target sees client IP

For TCP and TLS target groups, this generally requires a direct path to a target in the same VPC or a supported same-Region peered VPC.

Preservation is unavailable through Transit Gateway or Gateway Load Balancer inspection. PrivateLink traffic, IPv6-to-IPv4 translation and other unsupported paths present an NLB private address instead. Proxy Protocol v2 can carry connection metadata when the target supports it.

When ALB is the NLB target, NLB preserves the client IP to ALB, and ALB appends it to X-Forwarded-For.

The questions are:

Where should TLS end?

Must the target receive
the original encrypted stream?

Should client identity arrive as
HTTP metadata or network source?

gRPC can use either product

gRPC is an excellent example of why protocol names alone do not select the product.

gRPC commonly runs over HTTP/2.

An Application Load Balancer can understand gRPC as an application protocol.

With an HTTPS listener and a gRPC target-group protocol version, ALB can route calls based on the gRPC package, service and method. It supports unary and streaming call types and can use gRPC status codes for health checking.

CLIENT
  │
  │ gRPC call
  ▼
ALB
  │
  ├── understand HTTP/2
  ├── understand gRPC method
  └── select target group
          │
          ▼
      gRPC TARGET

An NLB can also carry gRPC because it can forward the underlying TCP connection.

CLIENT
  │
  │ HTTP/2 and gRPC inside TLS
  ▼
NLB
  │
  │ forward transport connection
  ▼
ENVOY OR gRPC TARGET

The NLB does not need to understand the gRPC method.

The downstream gateway or service does.

Therefore:

Need AWS to interpret gRPC
and route by service or method?

Choose ALB.


Need transparent transport forwarding
to an Envoy or gRPC endpoint?

Consider NLB.

For bfstore, the existence of gRPC does not automatically make NLB correct.

The required control point decides.

Static and privately published endpoint contracts point towards NLB

An ALB’s node addresses are service-managed and can change.

An NLB creates a network interface in each enabled Availability Zone and obtains a stable zonal address. An internet-facing NLB can use one Elastic IP per enabled zone.

NLB DNS NAME
   ├── AZ A static address
   ├── AZ B static address
   └── AZ C static address

This supports literal IP allow-lists and deterministic firewall rules. Clients should still use DNS where possible.

Static does not mean immortal. Removing an Availability Zone removes its NLB interface and address and terminates affected connections.

AWS PrivateLink endpoint services use NLBs to expose services through interface endpoints without giving consumers broad routed access to the provider VPC.

CONSUMER VPC
      │
      ▼
INTERFACE ENDPOINT
      │
      ▼
AWS PRIVATELINK
      │
      ▼
PROVIDER NLB
      │
      ▼
PRIVATE SERVICE

Combining NLB and ALB

When static addressing or PrivateLink is required alongside Layer 7 routing, AWS supports an ALB as an NLB target.

CLIENT OR PRIVATELINK CONSUMER
              │
              ▼
             NLB
              │
              ▼
             ALB
              │
              ▼
           TARGETS

The constraints are significant:

same account and VPC
one ALB per target group
TCP between the layers
matching target-group and ALB listener ports
IPv4 between NLB and ALB
one ALB targeted by no more than two NLBs

Registering an ALB also consumes substantial NLB target quota per Availability Zone.

The pattern adds two products, two health layers, more connection state and another failure boundary.

Use it only when both layers are genuine requirements.

ALB offers application-aware security controls

Because ALB understands HTTP, it can participate in controls that depend on HTTP semantics.

AWS WAF can evaluate web requests using conditions such as source address, request strings, size constraints and managed threat-detection rules.

ALB can also:

  • authenticate interactive users through OIDC
  • authenticate through Amazon Cognito
  • verify configured JWTs for service-to-service or machine-to-machine traffic
  • perform mutual TLS certificate verification
  • pass client certificate information to targets
  • redirect or return fixed HTTP responses

OIDC and Cognito actions handle user authentication flows.

JWT validation is a separate machine-oriented control. ALB currently supports RS256 JWTs, requires issuer and expiry claims, validates certain time claims when present and can validate additional configured claims.

HTTPS REQUEST
      │
      ▼
ALB
      │
      ├── TLS policy
      ├── AWS WAF
      ├── OIDC or Cognito
      ├── JWT validation
      ├── mutual TLS
      └── HTTP routing

These features do not move business authorisation into the load balancer.

The ALB may authenticate a caller or reject a malformed token.

It cannot decide whether that caller may refund order bf-8042 under bfstore’s domain rules.

Layer 7 infrastructure can provide a useful first control.

It does not become the entire security model.

NLB security groups do not turn it into ALB

An NLB can be created with security groups.

Those groups can filter traffic accepted by the NLB and can be referenced by target security groups so targets accept traffic through the load balancer rather than directly.

CLIENT
  │
  ▼
NLB SECURITY GROUP

network-level allow or deny
  │
  ▼
TARGET SECURITY GROUP

allow from NLB security group

The creation decision matters:

  • an NLB created with security groups can change them later
  • an NLB created without security groups cannot acquire them later
  • health checks are controlled by the NLB groups’ outbound rules, not their inbound rules
  • QUIC and TCP_QUIC listeners require an NLB with no security groups

Security groups filter source, destination port and protocol.

They do not make the NLB HTTP-aware and cannot inspect a request for a SQL-injection pattern.

That requires application-layer inspection, such as AWS WAF on an ALB or an appropriate proxy or firewall elsewhere in the path.

Security groups and protocol understanding are separate dimensions.

Health checks should test the contract that matters

ALB and NLB normally send new traffic to targets considered healthy.

The health check should match the failure the architecture needs to detect.

ALB health checks

ALB target groups support HTTP and HTTPS health checks.

For gRPC targets, a health check can use a gRPC method and configured successful status codes.

Can this target return
the expected response
for /health/ready?

NLB health checks

NLB target groups support TCP, HTTP or HTTPS active health checks depending on the configuration.

A TCP check asks:

Can a connection be established
to this port?

An HTTP check asks:

Can the target complete
this request successfully?

The deepest possible check is not always the correct one.

A health endpoint that calls ten downstream systems may remove every target during one database incident, turning a partial failure into complete unavailability.

A port check may leave a process in rotation even though it cannot serve one useful request.

Health is not an absolute traffic barrier

Both products can fail open.

If an ALB target group contains only unhealthy registered targets, ALB can route to those targets regardless of health.

NLB can similarly route to registered targets when all targets are unhealthy, and it can fail open when a target group is empty.

The health contract should therefore answer:

Should this target receive
new traffic during normal operation?

What should happen if
no healthy target remains?

Health checks are part of failure design, not a guarantee that an unhealthy target can never receive traffic.

Connection behaviour matters

ALB acts as a proxy with separate client-side and target-side connections.

It can manage backend connections independently of the client connection.

NLB forwards transport flows without ALB-style connection multiplexing. Targets may therefore receive a larger number of direct TCP connections and should be prepared for that connection volume.

This matters for:

  • long-lived connections
  • connection pools
  • target file-descriptor limits
  • server keepalive configuration
  • draining during deployments
  • retry storms
  • source-port capacity when translation occurs

Suppose 20,000 clients maintain persistent connections.

An application proxy can mediate the backend connection model.

A transport load balancer keeps the target-side flow behaviour closer to the client population.

ALB

request-aware proxy
separate front and backend connections


NLB

transport-level flows
targets experience connection behaviour
closer to the client population

Long-lived traffic does not automatically require NLB.

ALB supports WebSockets, HTTP/2 and gRPC streaming. A long-lived HTTP connection may fit ALB perfectly, while a short custom binary connection may still require NLB.

The relevant question is not:

How long does the connection last?

It is:

Which layer must understand
and own the connection?

The word load includes connection state, not merely requests per second.

Availability Zone behaviour differs

Both products create load-balancing capacity across enabled Availability Zones.

Application Load Balancer has cross-zone load balancing enabled at the load-balancer level. Supported target groups can narrow that behaviour.

Network Load Balancer has cross-zone load balancing disabled by default, although it can be enabled at load-balancer or target-group level.

NLB with cross-zone disabled

NLB NODE IN AZ A

routes to targets in AZ A


NLB NODE IN AZ B

routes to targets in AZ B

This preserves stronger zonal locality.

It also requires enough healthy capacity in every enabled zone.

NLB with cross-zone enabled

NLB NODE IN AZ A
        │
        ├── target in AZ A
        ├── target in AZ B
        └── target in AZ C

This can smooth uneven target placement.

It also broadens the data and failure path across zones. Depending on the client, NLB node and target placement, inter-AZ crossings can create Regional data-transfer charges. ALB’s load-balancer-level cross-zone behaviour does not use the same charging model.

The choice should align with:

  • zonal independence
  • target placement
  • cost
  • scaling symmetry
  • disaster behaviour
  • latency requirements

A load balancer spanning three zones does not prove that the application has three complete zonal stacks.

Targets and dependencies still need to be examined.

Internet-facing and internal are separate from ALB versus NLB

Both ALB and NLB can be created as:

internet-facing

or

internal

An internet-facing load balancer has publicly reachable load-balancer nodes.

An internal load balancer uses private addresses and is reachable only from networks with an appropriate private path to the VPC.

Both types forward traffic to registered targets using private addresses, so targets do not require public addresses merely because the load balancer is internet-facing.

This creates four ordinary combinations:

Product Scheme Example
ALB Internet-facing Public web or API entry
ALB Internal Private HTTP applications
NLB Internet-facing Public TCP, UDP or static-address endpoint
NLB Internal Private transport endpoint or PrivateLink service

The choice of scheme answers:

Where can clients reach
the load-balancer nodes from?

The choice of product answers:

What layer of traffic must
the load balancer understand?

These should not be fused into:

ALB is public.

NLB is internal.

Either product can serve either network role.

Kubernetes does not select the layer for me

Kubernetes Service, Ingress and Gateway API abstractions do not choose the external protocol boundary.

For bfstore’s public customer path, I would use a public ALB in public-entry subnets:

INTERNET
   │
   ▼
PUBLIC ALB
   │
   ├── HTTPS and approved TLS policy
   ├── AWS WAF
   ├── access logging
   └── security group
           │
           ▼
PRIVATE ENVOY GATEWAY TARGETS
           │
           ▼
BFSTORE SERVICES

The ALB owns the AWS public HTTP edge.

Envoy owns Kubernetes-native application routing, gateway policy and detailed gRPC or HTTP behaviour.

The ALB rule set can remain small:

HTTP → redirect to HTTPS
HTTPS → forward to Envoy Gateway

A private transport endpoint requiring static addresses, PrivateLink, TLS passthrough or a non-HTTP protocol may use an internal NLB.

Most Pod-to-Pod calls need neither product. Kubernetes Services, cluster DNS and platform-native gateway or mesh routing are usually the appropriate boundary.

Target registration still matters:

INSTANCE TARGET

load balancer
    │
    ▼
worker node and NodePort
    │
    ▼
Pod


IP TARGET

load balancer
    │
    ▼
Pod IP

The load-balancer product is only one part of the path.

The target type decides what actually receives the connection.

For a service that bfstore wants to publish privately across accounts, the design may require NLB.

CONSUMER ACCOUNT
       │
       ▼
INTERFACE ENDPOINT
       │
       ▼
AWS PRIVATELINK
       │
       ▼
INTERNAL NLB
       │
       ▼
PLATFORM SERVICE

If the endpoint exposes one transport service, the NLB may forward directly to it.

If it also needs HTTP-aware routing, bfstore could use the constrained NLB-to-ALB pattern described earlier:

CONSUMER
   │
   ▼
PRIVATELINK
   │
   ▼
NLB
   │
   ▼
ALB
   │
   ▼
HTTP SERVICES

That combination is justified only when the requirements explicitly contain both:

PrivateLink or static endpoint identity

and

Layer 7 request routing

PrivateLink should remain a narrow service-publication contract, not a replacement for every internal route.

The decision table I actually use

Requirement ALB NLB
Route by hostname or URL path Strong fit No HTTP awareness
Route by HTTP method, headers or query Strong fit No HTTP awareness
Route arbitrary source CIDRs Yes, with source-IP conditions No
Split IPv4 and IPv6 clients Possible through application rules and design Yes, with source-family listener rules
Weighted target groups Yes, request-aware rules Yes, for new connections
Native gRPC-aware routing Yes Pass through transport
Raw TCP No Yes
UDP No Yes
QUIC v1 pass-through No Yes, with significant constraints
WebSockets Yes Can pass supported TCP traffic
TLS termination Yes Yes
Target-owned TLS or mTLS handshake No transparent pass-through Yes, with TCP listener
Backend TLS certificate validation ALB does not validate target certificate NLB does not validate target certificate
AWS WAF association Yes No direct association
OIDC or Cognito user authentication Yes No
JWT validation for machine traffic Yes No
Static address per Availability Zone No customer-owned static ALB address Yes
Elastic IP per internet-facing zone No Yes
Original source as network identity Forwarded HTTP-header model Supported in qualifying paths
AWS PrivateLink endpoint service Not directly Yes
Register ALB as target Not applicable Yes, with constraints
Lambda target Yes No
Public or internal scheme Both Both
Non-HTTP protocol No Yes

The table is a shortcut.

The first question remains:

Which information must be visible
at the forwarding boundary?

Weak reasons and better questions

Weak reason Better question
“The application is a website.” Where should HTTP be interpreted?
“ALB is the normal option.” Which Layer 7 behaviour must AWS own?
“We may need path routing later.” Is duplicated routing ownership justified now?
“ALB is more secure.” Which specific WAF, authentication or HTTP control is required?
“The service uses gRPC.” Who must understand the gRPC service and method?
“NLB is faster.” Does the boundary require Layer 4 semantics, and what does measurement show?
“NLB handles more traffic.” Which measured capacity limit affects this architecture?
“NLB preserves the client IP.” Is native preservation supported on this exact path?
“We need port 443.” Where should TLS terminate?
“We use Kubernetes.” Which external protocol boundary does the workload require?
“We need end-to-end TLS.” Is re-encryption sufficient, or must one TLS session reach the target?
“The connection is long-lived.” Does the load balancer need application awareness or transport transparency?

A long-lived HTTP connection may fit ALB perfectly.

A short custom binary connection may still require NLB.

The protocol boundary matters more than the adjective attached to the workload.

Sometimes the answer is neither

Not every network boundary needs ALB or NLB.

Alternatives may include:

API Gateway

Useful when the desired boundary is an API-management service with features such as API lifecycle, usage plans or managed request processing.

CloudFront

Useful as a global HTTP content-delivery and edge-caching layer, often placed before an ALB or another origin.

Useful for publishing a private service contract, normally backed by NLB rather than broad routed connectivity.

Kubernetes Service

Useful for internal cluster traffic that does not need an AWS VPC load-balancer boundary.

Direct service discovery

Useful where clients should discover and connect to internal service endpoints through the platform’s own networking model.

Gateway Load Balancer

Useful for inserting and scaling virtual network appliances using a network-layer service chain.

The question should be:

Which boundary am I trying to create?

not:

Which of the two famous
load balancers should I purchase?

My design sequence

I choose the bfstore load-balancing path in this order.

1. Client, boundary and protocol

Who is connecting?

HTTP, gRPC, WebSocket,
raw TCP, UDP or QUIC?

2. Inspection layer

Must the boundary understand
the application request
or only the transport flow?

3. TLS and client identity

Where does TLS end?

Is re-encryption enough?

Must the target receive
the original encrypted session?

Header identity, certificate identity
or original network source?

4. Endpoint contract

DNS or literal static IPs?

PrivateLink?

Different IPv4 and IPv6 target groups?

5. Security and targets

AWS WAF, OIDC, Cognito,
JWT validation or mutual TLS?

Instances, Pod IPs, private IPs,
Lambda or another ALB?

6. Failure and operations

zonal or cross-zone?

what happens when no target is healthy?

connection draining?

QUIC restrictions?

source-preservation path?

NLB-to-ALB constraints and cost?

7. Product

LAYER 7 → ALB

LAYER 4 → NLB

BOTH → evaluate NLB → ALB,
but justify both layers
Area Core question
Layer Which information must influence target selection?
TLS Where must decryption and certificate validation occur?
Identity Header identity or original network source?
Endpoint DNS, static IPs or PrivateLink?
Targets What actually receives the connection?
Failure Zonal, cross-zone and fail-open behaviour?
Evidence HTTP request logs or transport-flow evidence?
Cost Are two layers solving two real requirements?

Only then does the product name become useful.

The mental model I am keeping

My earlier model was:

ALB for applications

NLB for performance

The stronger model is:

                         CLIENT TRAFFIC
                                │
                                ▼
                    REQUIRED DECISION LAYER
                                │
                 ┌──────────────┴──────────────┐
                 │                             │
                 ▼                             ▼
             APPLICATION                    TRANSPORT
               LAYER                          LAYER
                 │                             │
                 ▼                             ▼
       host, path, headers,             protocol, port,
       method, source CIDR,             flow, source family,
       gRPC service/method              source preservation
                 │                             │
                 ▼                             ▼
                ALB                           NLB
                 │                             │
       WAF, authentication,          static IPs, raw TCP,
       HTTP routing                  UDP, QUIC, PrivateLink

ALB asks:

What should happen to
this application request?

NLB asks:

Which target group and target
should receive this connection or flow?

ALB carries client identity as HTTP metadata.

NLB can preserve network source identity on supported paths.

ALB terminates TLS so AWS can apply application controls.

NLB TCP passthrough preserves the original TLS or mTLS session for the target.

The NLB-to-ALB pattern is justified only when the endpoint needs both transport-level features and application-layer routing.

Choose the layer at which the platform must make a decision. Then choose the AWS product that can see that layer clearly.

For bfstore’s public web and API edge, that points towards an ALB forwarding into Envoy Gateway.

For private services requiring static endpoints or PrivateLink, it may point towards NLB.

For ordinary service-to-service gRPC inside EKS, it may point towards neither.

The product name is the final line of the decision.

The protocol boundary writes everything above it.

References and further reading