---
title: Retries
description: Automatic retries for transient provider failures, with a configurable backoff curve and clear rules for what is and isn't retried.
---

`retries` retries transient failures automatically. Pass a number as shorthand for `{ max }`, or `{ max, backoff }` to control the wait between attempts. Set it on the constructor as a default and override it per call.

```ts lineNumbers
const files = new Files({
  adapter: s3({ bucket: "uploads" }),
  retries: { max: 3, backoff: ({ attempt }) => attempt * 500 },
});

// Opt a single write out of retries.
await files.upload("avatars/abc.png", file, { retries: 0 });
```

## What is retried

Only `Provider` failures — transient things like network blips, throttling, and 5xx responses. The classified codes are returned to you immediately, because retrying them can't help:

- `NotFound`, `Unauthorized`, and `Conflict` are deterministic — the same call fails the same way.
- Aborts and [timeouts](/timeouts) are never retried; retrying a cancelled call would defeat the cancellation.
- Uploads from a `ReadableStream` are never retried, because a consumed stream can't be safely replayed. Buffered bodies (`File`, `Blob`, `ArrayBuffer`, `Uint8Array`, `string`) retry normally.

See [Errors](/api/errors) for how codes are assigned.

## Backoff

The default backoff is exponential — `100 * 2 ** (attempt - 1)` ms, so 100ms, 200ms, 400ms, … — capped at 30 seconds, with no jitter. `attempt` is `1` for the first retry after the initial failure.

For high-fanout callers, supply your own `backoff({ attempt, error })` to add jitter or a different curve. A caller-supplied function is used verbatim — no cap is applied, so the ceiling is yours to set.

```ts lineNumbers
// Exponential with full jitter, still capped at 30s.
new Files({
  adapter: s3({ bucket: "uploads" }),
  retries: {
    max: 5,
    backoff: ({ attempt }) =>
      Math.random() * Math.min(30_000, 100 * 2 ** (attempt - 1)),
  },
});
```

Wire [`onRetry`](/api/onretry) to observe each scheduled attempt — its `attempt`, `delayMs`, and the triggering `error`.

## Bulk operations

`retries` is a single-key option; the array forms don't take it. They surface per-key failures in their `errors[]` result instead, so you can inspect or re-drive only the keys that failed. See [Errors](/api/errors#errors-in-bulk-operations).
