Back to all snippets
Library/Utilities/Retry with Backoff
typescriptadvancedasyncerror-handlingresilience

How to implement Retry with Backoff in Typescript

Retry failed operations with exponential backoff

Quick Answer

The `retry` utility re-runs an async function up to `maxAttempts` times, waiting `delay * backoff^(attempt-1)` milliseconds between each attempt before re-throwing.

Code Snippet

1async function retry<T>(
2  fn: () => Promise<T>,
3  options: {
4    maxAttempts?: number;
5    delay?: number;
6    backoff?: number;
7  } = {}
8): Promise<T> {
9  const { maxAttempts = 3, delay = 1000, backoff = 2 } = options;
10
11  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
12    try {
13      return await fn();
14    } catch (error) {
15      if (attempt === maxAttempts) throw error;
16      const waitTime = delay * Math.pow(backoff, attempt - 1);
17      await new Promise(resolve => setTimeout(resolve, waitTime));
18    }
19  }
20  throw new Error('Max attempts reached');
21}

What is Retry with Backoff?

Transient failures are common in distributed systems — a network blip, a rate limit, or a briefly unavailable service. This retry utility re-invokes an async function up to a configurable number of times, waiting progressively longer between attempts using exponential backoff to avoid thundering-herd effects.

How It Works

  1. 1The for loop runs the function up to `maxAttempts` times.
  2. 2On success the result is returned immediately.
  3. 3On failure, if more attempts remain, `setTimeout` waits `delay * backoff^(attempt-1)` milliseconds.
  4. 4On the last failed attempt the error is re-thrown so callers can handle it.

Common Use Cases

  • API calls - Retry failed fetch requests to external services
  • Database connections - Reconnect on transient connection failures
  • File operations - Retry file writes that fail due to locks
  • Webhooks - Retry failed webhook deliveries with backoff

Key Benefits

  • Exponential backoff reduces pressure on the failing service
  • Configurable max attempts, initial delay, and backoff multiplier
  • Re-throws the last error after all attempts are exhausted
  • Works with any async function regardless of its arguments

Common Mistakes to Avoid

  • Retrying on all errors — add an `isRetryable(error)` check to skip non-transient errors like 400 Bad Request.
  • Using a fixed delay without backoff — this can cause thundering-herd problems when many clients retry simultaneously.
  • Not setting a maximum delay cap — `delay * backoff^n` grows unboundedly; clamp it with `Math.min(waitTime, maxDelay)`.

Quick Tips

  • Click the "Copy" button above to copy the code to your clipboard
  • This code is production-ready and can be used in your projects immediately
  • Check out related snippets below for more typescript examples

Frequently Asked Questions

What is exponential backoff and why does it matter?

Exponential backoff doubles (or multiplies by a factor) the wait time between each retry. It prevents many clients from retrying simultaneously, which would overload a recovering service — known as the thundering herd problem.

About This Typescript Code Snippet

This free typescript code snippet for retry with backoff is production-ready and copy-paste friendly. Whether you are building a web app, API, or frontend interface, this advanced-level example will help you implement retry with backoff quickly and correctly.

All snippets in the Snippetly library follow typescript best practices and are tested for real-world use. You can adapt this code to work with React, Vue, Node.js, or any project that uses typescript.

Tags: async, error-handling, resilience  | Language: typescript  | Difficulty: advanced  | Category: Utilities

Build Your Own Snippet Library

Organise your team's code snippets with Snippetly. Share knowledge and boost productivity across your organisation.