← Back to Blog
Code Snippets August 5, 2026

JavaScript: Retry with Exponential Backoff, Jitter & Circuit Breaker

💻 Code Snippet — August 5, 2026

JavaScript: Retry with Exponential Backoff, Jitter & Circuit Breaker

Zero-dependency retry() that handles transient errors properly:

function retry(fn, {attempts=3, baseDelay=1000, maxDelay=30000, strategy="jitter", shouldRetry=()=>true, circuitBreaker:cb}= {}) {
    if(cb){cb.threshold??=5;cb.cooldownMs??=10000;cb.state??="closed";cb.failures??=0}
    const errors=[];
    async function attempt(){
        if(cb?.state==="open"&&Date.now()-cb.lastFailureTime<cb.cooldownMs)
            throw new Error("Circuit OPEN");
        try{
            const r=await fn();
            cb&&(cb.failures=0,cb.state==="half-open"&&(cb.state="closed"));
            return r;
        }catch(e){
            errors.push(e);
            cb&&(cb.failures++,cb.lastFailureTime=Date.now(),cb.failures>=cb.threshold&&(cb.state="open"));
            if(!shouldRetry(e)||errors.length>=attempts)throw e;
            const d=strategy==="jitter"?Math.random()*baseDelay*2**errors.length:baseDelay*2**errors.length;
            await new Promise(r=>setTimeout(r,Math.min(d,maxDelay)));
            return attempt();
        }
    }
    return attempt();
}


Usage:
retry(async()=>fetch('/api'),{
  attempts:3, strategy:"jitter",
  shouldRetry:e=>e.status>=500||e.status===429
});


Features: Jitter (prevents thundering herd), circuit breaker (open→half-open→closed), custom retry predicate, per-attempt timeout. Works in Node, browsers, Deno, Bun.

💡 Drop in utils/retry.js — never write retry logic inline again.