Teams that come to Cloudflare Load Balancing from an AWS ALB often configure everything correctly and then encounter behavior that their mental model doesn't explain: a client keeps arriving at the same origin for minutes after it failed, load distribution appears uneven between instances, and failover takes longer than health checks suggest. The product works, but it works differently than expected — because it operates on the DNS, not on the transport or application layer.
How Cloudflare Load Balancing really works
Cloudflare Load Balancing is a traffic distribution service that takes action at name resolution. When a client makes a DNS query for the balanced domain, Cloudflare Authoritative evaluates which origins are healthy, applies the configured steering rule, and returns the IP of the selected origin. From that point, the client connects directly to the source — or to the Cloudflare PoP, if the registration is proxied — and all requests from that session go to that destination until the TTL expires and the client needs to resolve the name again.
This means that load distribution happens via DNS resolution, not via HTTP request. Two concurrent clients that resolve the domain in the same second can be assigned different origins. A single client that resolves the name once and keeps the connection open stays on the same origin indefinitely. If there are ten instances running behind an ALB, the ALB distributes requests among them with each new request. With Cloudflare LB, the granularity is the customer, not the request.
The health checks system corrects the path when a source fails. Cloudflare performs active health checks from multiple PoPs — not a single point — against each registered origin. When the percentage of failures exceeds the configured threshold, the source is marked as degraded and removed from the resolution pool. New clients that resolve their name after this tag no longer receive the IP of the problematic source. Clients that have already resolved the name and have the IP cached continue trying to connect until the TTL expires. Failover therefore has two latency components: the time for the health check to detect and mark the failure, and the remaining TTL of clients that have already resolved.
The pricing model and what it covers
The Cloudflare Load Balancing base plan costs $5 per month and includes two origin pools, five origins per pool, and configurable health checks. The additional charge of $0.50 per 500,000 health check queries applies to the volume generated by the checks — with 60-second intervals and distribution across multiple PoPs, the monthly volume rises quickly, but is still in a reasonable range for active-passive setups with small pools.
For a simple active-passive setup — a main pool with two sources and a fallback pool — the monthly bill is under $10 in most scenarios. For more elaborate architectures with multiple regional pools and granular health checks per PoP, the cost increases, but remains competitive when compared to the operational overhead of managing manual failover between regions.
Geo Steering: routing by customer's geographic origin
Geo Steering is the functionality that turns the Load Balancer into a true geographic routing layer. The configuration associates regions — specific continents or countries — with source pools. Brazilian customers resolve the domain and receive the IP of the origin in São Paulo. European customers receive the IP of the origin in Frankfurt. Cloudflare authoritative identifies the geographic location of the resolver that made the query and returns the response from the corresponding pool.
When the regional pool becomes unavailable — all origins in it marked as degraded — Cloudflare automatically drops to the configured global fallback pool. The European client whose Frankfurt pool is outside receives the IP from São Paulo or any other pool that is healthy, without manual intervention. This automatic fallback mechanism is what makes Geo Steering useful for geographic high availability, not just latency optimization.
Cookie session affinity complements geographic routing for cases where the same instance needs to serve the same client across multiple DNS resolutions. Cloudflare injects a cookie into the HTTP response that identifies the selected origin, and Load Balancer uses this cookie to return the client to the same origin on subsequent resolutions, even if the TTL has already expired. For stateless applications this is irrelevant; For sessions that store context in instance memory, it is the mechanism that prevents experience breakage during normal TTL re-resolutions.
The distinction that changes the design of architecture
An ALB operates at layer 7. It receives TCP connections, inspects HTTP headers, applies path and header routing rules, and distributes each individual request to an instance of the backend pool. It sees every request. You can do path-based routing — /api goes to one group of instances, /static goes to another. Can inject or modify headers. Has visibility over the request body if the protocol allows it.
Cloudflare LB doesn't see individual requests. It answers DNS queries. There is no way to inspect path /api because the path does not even exist at the DNS layer — it only appears after the client has established the TCP connection with the origin and sent the HTTP GET. This is no accidental limitation; it's the natural consequence of operating on the wrong protocol for that level of granularity.
The pattern that combines the two solves different problems at each layer. Cloudflare LB takes care of geographic routing and failover between regions: customers in Brazil arrive in São Paulo, customers in Europe arrive in Frankfurt, and if São Paulo goes down, the traffic automatically migrates. Within each region, an ALB or nginx distributes requests among the pool instances, performs path-based routing, and manages the load at the request level. The two coexist without conflict because they solve problems at different layers of the stack.
What health checks mean for failover SLA
The speed of failover depends on three variables: the health check interval, the number of consecutive failures required to mark a source as degraded, and the TTL of the DNS record. With health checks every 60 seconds and two consecutive failures as a threshold, the worst case for detection is 120 seconds. Adding the TTL — which for proxied records is 60 seconds — the maximum failover window is around 3 minutes.
Reducing the health check interval speeds up detection, but increases the volume of queries charged. The break-even point depends on the service availability SLA. For systems where 3 minutes of partial failure is acceptable — the dead origin serves zero new clients upon detection, but clients with active cache still try for up to the TTL — the default setup is adequate. For systems where any diversion of traffic to a degraded source is unacceptable, the combination of low TTL, short interval health check and at least two PoPs checking in parallel reduces the window to less than 2 minutes in practice.
The point that teams with ALB backgrounds underestimate is that Cloudflare LB does not drop active connections when an origin is marked as degraded. It stops returning that IP in new DNS resolutions. Clients that already have the IP cached continue trying. The TCP connection timeout or application error is what the client will experience until the TTL expires and a new resolution returns a healthy IP. The actual impact depends on what fraction of active clients have fresh cache versus expired cache at the time of the failure.
Also read
- Cloudflare DNS: network infrastructure that goes far beyond resolving names
- DNS proxied vs DNS only: what changes and when each mode makes sense
- DNSSEC with Cloudflare: what it protects, what it doesn't protect and how to activate without problems
- Cloudflare Email Routing: receive email on your domain — and what's not included
- KV vs R2 vs Cache API: When to use each Cloudflare storage tier
- Cloudflare KV: What does globally distributed mean when you need to write
