Skip to content

Load Balancing: Layer 4 vs Layer 7

Core Concept LearningJuly 4, 20264 min readUpdated July 21, 2026

A load balancer spreads connections so one machine does not take all the pain. Layer 4 routes on IP and port — fast and protocol-agnostic. Layer 7 reads HTTP hosts, paths, and headers — smarter routing, more work per request. The horizontal vs vertical scaling guide explains when adding balanced instances is the correct capacity move.

Wrong layer means either blind TCP fan-out when you needed /api vs /static, or HTTP parsing overhead when you only needed raw throughput. This article compares both, shows a request path with health-check failure, and gives a decision rule you can defend with evidence. For a concrete L7 configuration, continue with the NGINX gateway guide.

Layer 4 vs Layer 7 load balancing
Layer 4 vs Layer 7 load balancing

Layer 4 (Transport) Load Balancing

An L4 balancer sees source/destination IP and port — not HTTP paths. A client connects to :443; the balancer picks a backend (round-robin, least connections, or IP hash) and forwards the TCP (or UDP) stream. It does not terminate TLS or read cookies unless you add a separate terminator.

Use L4 for non-HTTP workloads (databases, many gRPC/WebSocket setups) or when you want minimal per-connection work at the edge. AWS Network Load Balancer, HAProxy in TCP mode, and Linux IPVS operate here. Pass the real client IP with PROXY protocol when backends need it.

Skimmer: L4 and L7 make decisions from different request data.
LayerRoute usingUse whenTrade-off
L4IP, port, connection stateRaw TCP/UDP or protocol-agnostic fan-outCannot route by HTTP host, path, or header
L7HTTP host, path, header, cookieTLS termination and content-aware routingParses and operates on application traffic
L4: distribute connections by IP/port
L4: distribute connections by IP/port

Quick reference

  • Best for: TCP/UDP, databases, protocol-agnostic fan-out, high connection counts.
  • Strengths: low per-packet work; any protocol on the port.
  • Weaknesses: no URL routing; no content-based decisions.
  • Algorithms: round-robin, least connections, IP hash (IP sticky).
  • Use PROXY protocol when backends must see the original client address.
  • When not to use alone: you need path/host routing or cookie affinity on HTTP.
HAProxy TCP mode with active checks
1# haproxy.cfg2global3  log stdout format raw local04 5defaults6  mode tcp7  timeout connect 2s8  timeout client  30s9  timeout server  30s10 11frontend postgres_in12  bind *:543213  default_backend postgres_nodes14 15backend postgres_nodes16  balance leastconn17  option tcp-check18  server db1 10.0.1.10:5432 check inter 2s fall 2 rise 219  server db2 10.0.1.11:5432 check inter 2s fall 2 rise 2
Failure drill and expected check
1# Validate, then start HAProxy with the config.2haproxy -c -f ./haproxy.cfg3haproxy -f ./haproxy.cfg -db4 5# Expected: repeated connections to localhost:5432 succeed.6for i in 1 2 3; do nc -zv 127.0.0.1 5432; done7 8# Failure path: stop db1. After two failed 2s checks, HAProxy9# marks it DOWN and new connections use db2. Stop both backends:10# nc fails instead of routing to an unhealthy server.

Remember this

Choose L4 when protocol flexibility and low overhead matter more than HTTP awareness.

Layer 7 (Application) Load Balancing

An L7 balancer understands HTTP(S). It can terminate TLS, read Host, path, cookies, and headers, then route /api/* to the API pool and / to the web pool. That enables host-based vhosts, sticky cookies, rewrites, and WAF hooks. AWS Application Load Balancer, NGINX, and Traefik are common L7 choices.

Request trace: Client → L7 (TLS) → match Host + path → select upstream → proxy → response. In open-source NGINX, max_fails and fail_timeout implement passive checks based on failures from real proxied requests; they do not periodically probe /health. Active HTTP probes require NGINX Plus or another health-checking component.

L7: route by URL path and headers
L7: route by URL path and headers

Quick reference

  • Best for: HTTP APIs, microservices path routing, TLS termination at the edge.
  • Strengths: path/host routing and header rewrites; health-check behavior depends on the product/edition.
  • Open-source NGINX max_fails is passive; periodic active probes are an NGINX Plus feature.
  • Weaknesses: more CPU per request than L4; HTTP-centric by default.
  • Route by path or host; use cookie stickiness only when the app is not yet stateless.
  • Do not load-balance public static assets a CDN can cache.
Open-source NGINX — routing + passive failure detection
1upstream api_pool {2  least_conn;3  server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;4  server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;5}6 7server {8  listen 443 ssl;9  server_name api.example.com;10 11  location /api/ {12    proxy_pass http://api_pool/; # /api/health reaches upstream /health13    proxy_set_header Host $host;14    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;15    proxy_next_upstream error timeout http_502 http_503;16  }17 18}
Upstream endpoint used by /api/health requests
1// GET /health on each upstream; open-source NGINX observes2// its result only when a client request is proxied to this path.3app.get("/health", async (_req, res) => {4  try {5    await db.query("SELECT 1");6    res.status(200).json({ status: "ok" });7  } catch {8    res.status(503).json({ status: "degraded" });9  }10});

Remember this

Choose L7 when HTTP routing, TLS termination, and content-aware decisions are required.

Combining L4 and L7 in Production

Many production edges stack both: L4 (or DNS/anycast) at the outer perimeter for connection distribution and DDoS absorption; L7 inside for TLS, path routing, and service dispatch. In Kubernetes a common shape is Internet → cloud LB → Ingress (L7) → Service → Pod. Pure TCP/gRPC or database traffic may stay on L4 services end to end.

Decision evidence: If you only need “spread TCP to N identical nodes,” L4 is enough. If product routing depends on URL, headers, or hostnames, you need L7 somewhere. Measure p95 latency and error rate before and after moving TLS termination — do not assume L7 is “always slower enough to matter” without your workload.

Stacked in production: L4 at the edge, L7 inside for HTTP intelligence
Stacked in production: L4 at the edge, L7 inside for HTTP intelligence

Quick reference

  • Edge: L4 for high-connection entry and simple TCP fan-out.
  • Application: L7 for SSL, path routing, microservice dispatch.
  • Internal: L4 often fine for service-to-service gRPC or DB pools.
  • Health checks: configure the actual balancer/edition to call an HTTP endpoint that reflects dependencies.
  • Attach autoscaling target groups so new instances join automatically.
  • Multi-region: GeoDNS or anycast entry, then local L7.

Remember this

Stack L4 at the edge for connections and L7 inside for HTTP intelligence — pick by routing need, not fashion.

Recover One Health-Check Failure End to End

Trigger. db1 behind the HAProxy TCP pool above stops accepting connections — a crash, an OOM kill, a bad deploy. Symptom. For the next few seconds, some client connections still route to db1 and hang or reset, because HAProxy hasn't yet proven the backend is actually down; a health check is a sampled signal, not an instantaneous one.

Root mechanism. The config's fall 2 requires two consecutive failed checks at inter 2s before HAProxy marks a server DOWN — a deliberate debounce against a single dropped packet flapping a healthy server in and out of rotation, at the direct cost of up to ~4 seconds where new connections can still land on a backend that's actually dead. Recovery: once db1 fails its second check, HAProxy removes it from the pool and every new connection routes to db2 only — no code change, no manual intervention, the mechanism the config already declared. Verification: run repeated nc -zv connection attempts through the failure window and confirm they shift from intermittent failures to consistently succeeding against db2 alone once the fall threshold is crossed. Prevention: tune fall/rise/inter against your actual failure tolerance — a lower fall detects failure faster but risks flapping a backend with occasional transient blips; verify the trade-off against a real failure injection, not just the default values from a tutorial.

Health-check drill: db1 fails two checks, traffic shifts to db2
Health-check drill: db1 fails two checks, traffic shifts to db2

Quick reference

  • Trigger: a backend stops accepting connections without warning.
  • Symptom: some new connections still land on the dead backend until the check threshold is crossed.
  • Root mechanism: fall 2 at inter 2s is a deliberate debounce — real but bounded detection delay, not a bug.
  • Recovery: HAProxy's own mechanism removes the backend from rotation with no manual step required.
  • Prevention: tune fall/rise/inter against a real failure injection test, not default values assumed to be correct.

Remember this

A health check's fall/rise thresholds are a deliberate trade between fast failure detection and flapping-avoidance — the bounded detection delay during that trigger is expected behavior, not a defect to eliminate to zero.

Key takeaway

L4 optimizes for transport distribution; L7 adds HTTP-aware control. Systems may use either or both at different boundaries. Defend the choice with required routing behavior and measured latency/error impact, not vendor throughput claims.

Practice (20 min): run two local app instances with the /health endpoint above and point the shown open-source NGINX upstream at both. Stop one instance, send repeated curl --fail http://localhost/api/health requests, and observe passive failures plus sibling responses in the access/error logs. If you need removal without client traffic, configure an active-check product or orchestrator and state that prerequisite explicitly.

Share:

Related Articles

Many teams still introduce NGINX as “just a web server.” In production it usually sits in front of your app: clients hit

Read

A product manager says PAY-204: next Friday's campaign may double checkout traffic for three hours. The beginner mistake

Read

A multi-tenant analytics platform partitions incoming events by tenant_id, hashed onto 16 shards — a design that looked

Read

Keep learning

Follow a structured path or browse all courses to go deeper.