# retryLink

> Retry failed calls, by default queries that failed outside their typed errors, with backoff.

`retryLink()` retries a failed call by running the rest of the chain again. By default it retries queries only, on errors outside the procedure's typed union (network failures, 5xx), up to three times, waiting 200, 400 and 800 ms. It never retries an aborted call.

```ts
import {
  createTrpcClient,
  httpLink,
  retryLink,
  routerType,
} from '@trpc12/trpc/client';

const client = createTrpcClient({
  router: routerType<AppRouter>(),
  links: [retryLink(), httpLink({ url: 'http://localhost:3000/trpc' })],
});
```

- `retries`: how many times to retry, 3 by default.
- `retry({ op, error, attempt })`: whether to retry this failure. It replaces the default rule, so check `op.type` yourself before retrying mutations.
- `delayMs(attempt, error)`: how long to wait before a retry, `2 ** attempt * 100` by default.

Put it before the terminating link, and after [`dedupeLink`](https://v12.trpc.io/v12/docs/client/links/dedupe.md), so a shared query is retried once for all its callers.

## Waiting out a rate limit

`delayMs` gets the error, so a retry can wait as long as the server asks. A server that rate-limits can fail with `TOO_MANY_REQUESTS` and the wait in `data.retryAfter`, in milliseconds. Links see every error untyped, so `data` is `any` here:

```ts
retryLink({
  retry: (opts) => opts.error.code === 'TOO_MANY_REQUESTS',
  delayMs: (attempt, error) =>
    error.code === 'TOO_MANY_REQUESTS'
      ? error.data.retryAfter
      : 2 ** attempt * 100,
});
```

This `retry` replaces the default rule, so only rate-limited calls are retried, mutations included.
