A load balancer is easy to stand up and easy to get subtly wrong. A health check that hammers the database, a 300-second drain that makes every deploy crawl, a stale TLS policy, an orphaned load balancer billing by the hour - these are the everyday ways ELB v2 automation costs money or drops traffic.
Walk this list once now, then use it as a review checklist before shipping any code that creates or manages load balancers, listeners, or target groups. All examples use elbv2 / @aws-sdk/client-elastic-load-balancing-v2.
Pick the type deliberately.Type is fixed at creation - application for HTTP routing, network for L4, static IP, or lowest latency. Switching means a new load balancer.
Use an ALB for HTTP routing. Path, host, and header rules on one ALB beat running many single-purpose load balancers.
Use an NLB for non-HTTP or fixed IPs. TCP/UDP workloads, IP allowlists, and extreme throughput belong on an NLB with SubnetMappings.
Spread across at least two AZs. List subnets in multiple Availability Zones so one AZ failure does not take the service down.
Keep the health endpoint shallow. A /healthz that touches the database marks the whole fleet unhealthy when that dependency slows; check only the process is alive.
Set an explicit matcher. A range like 200-299 is safer than a lone 200 if the endpoint can return a 204.
Tune detection time on purpose. Failure detection is roughly UnhealthyThresholdCount x HealthCheckIntervalSeconds; lower both to fail fast, not so low that targets flap.
Keep timeout below interval.HealthCheckTimeoutSeconds must be less than HealthCheckIntervalSeconds or the API rejects it.
Create the target group with deliberate, shallow health-check settings.
Set deregistration delay to fit your requests. Lower the 300s default to just above your longest normal request (often ~30s) so deploys drain cleanly without crawling.
Wait for draining to finish. Poll DescribeTargetHealth until a removed target leaves draining for unused before terminating it.
Confirm new targets are healthy before cutover. A target is initial until it passes checks; only shift traffic once it is healthy.
Use slow start for cold targets. Ramp traffic with slow_start.duration_seconds so a fresh target is not overwhelmed before caches warm.
Set the deregistration delay so connection draining matches your traffic.
Wait on the availability waiter. Use load_balancer_available (boto3) or waitUntilLoadBalancerAvailable (SDK v3) before adding listeners instead of a sleep.
Tag every resource. Tag load balancers, target groups, and listeners with Name, Environment, and Owner so nothing is orphaned or unattributable.
Delete unused load balancers. An idle ALB/NLB bills per hour plus capacity units; tear down what a deploy or test left behind.
Weigh NLB cross-zone cost. Cross-zone is free on an ALB but adds inter-AZ transfer on an NLB - enable it only when target counts are uneven.
Rely on built-in retries. Both SDKs retry throttling and transient errors with backoff; tune max attempts rather than reimplementing retries.
Log the request id on failure. Capture ResponseMetadata.RequestId (boto3) or $metadata.requestId (SDK v3) for support and correlation.
Use an ALB for HTTP/HTTPS with path or host routing, and an NLB for TCP/UDP, a fixed IP, or the lowest latency at very high scale. The type is fixed at creation, so decide first.
What makes a good health check?
A shallow, cheap endpoint that only confirms the process is alive, an explicit matcher like 200-299, and detection time tuned through interval x unhealthy count so it fails fast without flapping.
How do I get zero-downtime deploys?
Set deregistration_delay.timeout_seconds to just above your longest request, wait for removed targets to finish draining, and confirm new targets are healthy before cutting over.
Why is my whole fleet unhealthy at once?
The health endpoint probably touches a shared dependency that got slow, so every probe fails together. Keep the check shallow and independent of the database or downstream services.
How should I handle TLS?
Terminate on the load balancer with an auto-renewing ACM certificate in the same region, choose a modern ELBSecurityPolicy-TLS13-*, and redirect HTTP to HTTPS so no client stays on plaintext.
Do I need to write retry logic for ELB calls?
Usually no. Both SDKs retry throttling and transient errors with backoff. Tune retry mode and max attempts instead of reimplementing it.
Should I wait after creating a load balancer?
Yes. Use the load_balancer_available waiter before adding listeners; a new ALB/NLB is provisioning for a couple of minutes and is not ready immediately.
What is the most common load-balancer cost leak?
An idle load balancer left running - it bills per hour plus capacity units whether or not it serves traffic. Tag resources and delete the ones a test or deploy abandoned.
Why is cross-zone balancing off on my NLB?
It is off by default on an NLB (unlike the ALB, where it is always on and free). Enable load_balancing.cross_zone.enabled for even spread, accepting possible inter-AZ transfer cost.
How do I keep deploys from crawling?
Lower the 300-second default deregistration delay to just above your longest normal request. Too high and every rolling replacement waits five minutes per target.
Where should the ACM certificate live?
In the same region as the ALB or NLB. Only CloudFront requires the certificate in us-east-1; regional load balancers use a regional certificate.
How do I make sure targets are ready before sending traffic?
Poll DescribeTargetHealth and shift traffic only once the state is healthy; a target stays initial until it passes the configured number of checks.