Configure retry limits, eligible methods and statuses, and the delay between attempts; add a custom decision when the default retry rules do not match your API. Use retries for requests that can safely be repeated after a transient failure.
Set retry limits and eligibility
Set retry defaults on a ky instance when several calls share the same policy, or pass retry on an individual request. The value can be a number, which sets only the retry limit, or a RetryOptions object.
-
Create an instance with the retry policy and make a request:
tsimport ky from 'ky'; const api = ky.extend({ retry: { limit: 3, methods: ['get'], statusCodes: [429, 503], afterStatusCodes: [429, 503], maxRetryAfter: 30_000, backoffLimit: 2_000, jitter: true, }, }); const run = async (): Promise<void> => { const report = await api.get('https://api.example.com/reports').json<unknown>(); console.log(report); }; void run();The instance makes GET requests eligible for up to three retries on the selected statuses. For those statuses, Ky uses retry timing headers when available and caps a header-provided delay at 30 seconds. Otherwise it uses the configured backoff and jitter. If an attempt succeeds,
.json()resolves with the parsed response body; if retries are exhausted, the request rejects with its error.
Customize the retry decision
Use shouldRetry to decide whether a failed attempt merits another try. Ky calls it only after the retry limit and method checks pass. Return true to retry, false to stop, or undefined (or no value) to keep Ky's default decision. A true result bypasses the default timeout and status-code checks, but not the retry limit or method checks.
-
Add a decision for rate limits while leaving other failures to the default rules:
tsimport ky, {HTTPError} from 'ky'; const api = ky.extend({ retry: { limit: 3, methods: ['get'], statusCodes: [429, 503], shouldRetry: ({error, retryCount}) => { if (error instanceof HTTPError) { const status = error.response.status; if (status === 429) { return retryCount <= 2; } if (status >= 400 && status < 500) { return false; } } return undefined; }, }, }); const run = async (): Promise<void> => { const report = await api.get('https://api.example.com/reports').json<unknown>(); console.log(report); }; void run();retryCountstarts at1for the first retry. This policy allows at most two retries for429, rejects other4xxfailures without retrying, and delegates other failures to Ky's default checks. For example, a503remains eligible under the configuredstatusCodes; recognized network errors also use the default behavior for retriable methods.shouldRetrydecides whether Ky retries. ThebeforeRetryhook runs only after Ky confirms the retry and is where you modify the request.
Retry options
The defaults below apply when you provide an object and omit a field. Set limit to 0 to disable retries. A numeric retry value is shorthand for limit; the other defaults remain in effect.
| Option | Type | Default | What it does |
|---|---|---|---|
limit | number | 2 | Sets the number of retries. It must be a finite, non-negative integer. |
methods | readonly HttpMethod[] | ['get', 'put', 'head', 'delete', 'options', 'trace', 'query'] | Restricts retries to these HTTP methods. |
statusCodes | readonly number[] | [408, 413, 429, 500, 502, 503, 504] | Lists HTTP response statuses eligible for retry. 413 is retried only when the response has a retry timing header. |
afterStatusCodes | readonly number[] | [413, 429, 503] | Selects statuses that use retry timing headers. Each status must also appear in statusCodes. |
maxRetryAfter | number | Infinity | Caps a delay obtained from a retry timing header. |
backoffLimit | number | Infinity | Caps each calculated retry delay in milliseconds. |
delay | (attemptCount: number) => number | attemptCount => 0.3 * (2 ** (attemptCount - 1)) * 1000 | Calculates a delay in milliseconds; the attempt count starts at 1. |
jitter | boolean | ((delay: number) => number) | undefined | Adds random variation to calculated retry delays. true uses full jitter. Jitter does not change a delay supplied by a server timing header. |
retryOnTimeout | boolean | false | Enables retries when a request times out before a response arrives. A timeout while a shortcut method reads a received response body is not retried. |
shouldRetry | (state: ShouldRetryState) => boolean | void | Promise<boolean | void> | undefined | Applies a custom retry decision after limit and method checks pass. |
Pitfalls
- With retries enabled, Ky buffers a streaming request body in memory so it can replay it. For a large streaming upload that does not need retries, set
retry: {limit: 0}. - A retry request returned from
beforeRetryor supplied toky.retry({request})is used as-is and is not sanitized. If it targets another origin, remove credentials you do not want forwarded. - Ky automatically retries recognized network errors for retriable methods. Other unrecognized errors are not retried by default; use
shouldRetrywhen your runtime or application needs a different decision. - When Ky populates
HTTPError.data, it consumes the response body. Do not then callerror.response.json()or another body method; useerror.datainstead. See Ky errors and validation.
Was this page helpful?