Skip to content
Zap Studio
retry
Esc
navigateopen⌘Jpreview
On this page

exponentialBackoff

Retry with exponentially growing delays, capped at an upper bound.

exponentialBackoff(...) creates a policy that doubles the delay after each failure, up to a hard cap, reducing pressure on unstable upstream services.

Import

import { exponentialBackoff } from "@zap-studio/retry";

Configuration

import { exponentialBackoff } from "@zap-studio/retry";

const policy = exponentialBackoff({
  maxAttempts: 6,
  baseDelayMs: 100,
  maxDelayMs: 5_000,
});
Option Type Default Description
maxAttempts number Maximum number of attempts (including the first) before giving up.
baseDelayMs number Initial delay in milliseconds, doubled after each retry.
maxDelayMs number Hard upper bound in milliseconds for the computed delay.
jitter "full" | "equal" | JitterOptions Randomizes the capped delay. See Jitter.

All options are required except jitter.

Delay Model

The delay before the next retry is computed from the failed attempt number:

delayMs = Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1));

With baseDelayMs: 100 and maxDelayMs: 2_000:

  • after attempt 1 → wait 100 ms
  • after attempt 2 → wait 200 ms
  • after attempt 3 → wait 400 ms
  • after attempt 4 → wait 800 ms
  • after attempt 5 → wait 1_600 ms
  • after attempt 6 → wait 2_000 ms (capped)

The policy stops retrying when attempt >= maxAttempts, returning a decision with reason: "max-attempts-reached".

When to Use

Use exponentialBackoff when:

  • retries target shared or networked services
  • transient failures are common
  • aggressive immediate retries could amplify outages

For predictable, constant intervals, use fixedDelay instead.

Example

import { exponentialBackoff, runRetryPolicy } from "@zap-studio/retry";
import { $fetch } from "@zap-studio/fetch";

const policy = exponentialBackoff({
  maxAttempts: 5,
  baseDelayMs: 100,
  maxDelayMs: 2_000,
});

const user = await runRetryPolicy(policy, async () => {
  const response = await $fetch("https://api.example.com/users/1", {
    throwOnFetchError: true,
  });
  return await response.json();
});

Last updated on September 15, 2026

Was this page helpful?