On this page
What Is Exponential Backoff?
Exponential backoff is a retry strategy that waits progressively longer between attempts. Learn why it beats retrying instantly and how to use it.
Quick answer
- Exponential backoff means each retry waits longer than the last — 1s, 2s, 4s, 8s — instead of hammering instantly.
- It gives a failing service time to recover and prevents retry storms that make outages worse.
- Add jitter (randomness) to the wait, or synchronized retries from many clients will hit the server in waves.
Why does retrying instantly make things worse?
When a service is overloaded or down, every client retrying immediately re-creates the exact load that caused the failure. This is the thundering herd problem: one outage plus naive retries becomes a retry storm that extends the outage. Waiting before retrying gives the system time to recover and spreads retries out over time.
How is exponential backoff implemented?
After attempt n, wait base_delay × 2^n (for example, 1s, 2s, 4s, 8s, capped at a max like 60s), then try again. Add full jitter — a random delay between zero and the current wait — so thousands of clients don’t retry in lockstep. Cap the number of attempts (usually 3-6) and give up gracefully, reporting the failure rather than retrying forever.
import random, time
def request_with_backoff(url, max_attempts=5):
delay = 1
for attempt in range(max_attempts):
resp = requests.get(url)
if resp.status_code < 500:
return resp
time.sleep(random.uniform(0, delay)) # full jitter
delay = min(delay * 2, 60)
raise RuntimeError(f"gave up after {max_attempts} attempts")When should I NOT retry?
Do not retry on client errors (4xx) — retrying a 401 or 422 will never succeed and only adds load. Retry only on transient failures: timeouts, 429 (rate limited), 5xx, and network errors. Respect the Retry-After header if the server sends it, and treat idempotency as a requirement: if a retry can double-charge or double-send, your operation must be idempotent first.
Where this bites vibecoders
AI assistants generate retry loops readily but often get them wrong: no delay, no cap, no jitter, or retries on 4xx errors. The classic failure is a vibecoded webhook handler that retries instantly against an overloaded API and makes a small outage into a billing disaster. Exponential backoff with jitter is a few lines of code that converts an outage amplifier into a graceful recovery mechanism.
Where AI coding assistants get this wrong
- Retrying immediately in a tight loop, creating a self-inflicted retry storm.
- Retrying 4xx client errors that will never succeed.
- Using fixed waits without jitter, so many clients retry in synchronized waves.
- Retrying non-idempotent operations (payments, sends) without an idempotency key.
Checklist
- Retry only transient failures: timeouts, 429, 5xx, network errors.
- Use exponential backoff with full jitter and a max delay.
- Cap attempts and surface the failure instead of retrying forever.
- Make retried operations idempotent before enabling automatic retries.
FAQ
What is the difference between backoff and jitter?
Backoff is the increasing wait between retries. Jitter is random variation added to that wait. Jitter exists to stop clients that started retrying at the same time from hitting the server in synchronized waves — the randomness spreads them out.
What is the best retry schedule?
There’s no single best, but a common pattern is starting at 1 second, doubling each attempt, capping at 30-60 seconds, and stopping after 3-6 attempts. What matters more than the exact numbers is having a cap, jitter, and a rule about which errors are retryable.
Related topics
- How to Add Retry Logic to API Calls
- What Is a Dead Letter Queue?
- What Is Idempotency (and Why Does It Matter for APIs)?
- What Is Rate Limiting?
- How to Build a Background Job Queue
- What Is a Webhook?