Skip to content
D
Documentation

The request lifecycle

concept
1 min readUpdated

Ky runs hooks at specific points as a request becomes a response or a retry. The value a hook returns can replace a request or response, skip work, or start another attempt.

How the hooks fit together

Configure the lifecycle through Hooks on a ky instance.

mermaid
flowchart TD
    A["init hooks: edit options synchronously"] --> B["beforeRequest hooks: edit or replace request"]
    B -->|"Request continues"| C["Fetch"]
    B -->|"Response returned"| F["afterResponse hooks"]
    C --> F
    F -->|"Response or void"| G{"Non-2xx and throwHttpErrors enabled?"}
    F -->|"ky.retry()"| H["Retry decision and delay"]
    G -->|"No"| I["Return response"]
    G -->|"Yes"| H
    H -->|"Retry confirmed"| J["beforeRetry hooks"]
    J --> C
    H -->|"No retry"| K["beforeError hooks"]
    K --> L["Throw error"]

init edits the options before Ky constructs the request. beforeRequest runs once, before retry handling begins. If it returns a Request, that becomes the outgoing request and the remaining beforeRequest hooks still run. If it returns a Response, Ky skips the network request and the remaining beforeRequest hooks. Returning nothing leaves the request flow unchanged.

After a response arrives, afterResponse receives a clone, so a hook can inspect its body without consuming the response Ky continues with. Returning a Response replaces the current response; returning nothing keeps it. A non-2xx response is checked after these hooks. When HTTP errors are enabled, Ky retries eligible failures before it ultimately throws an HTTPError.

beforeRetry runs only after Ky has decided to retry, with a retry count of at least one. A returned Request replaces the retry request; a returned Response supplies the response instead of another fetch. Returning ky.stop stops the retry flow without throwing and leaves no response to read, so body shortcuts such as .text() are not suitable for that case. beforeError runs as Ky is about to throw an error; return an Error to keep or replace the error that reaches the caller. An exception from an init hook is synchronous and bypasses beforeError.

Keep hook errors out of retry handling

For how shouldRetry, beforeRetry, and returned requests or responses shape the flow, see How Ky works. This page adds the error boundary: exceptions from beforeRequest and afterResponse do not trigger retries, while an init exception propagates synchronously and bypasses beforeError.

For retry eligibility and delay behavior, see Retry failed requests. For handling the errors that leave the lifecycle, see Ky errors and validation.

Was this page helpful?

The request lifecycle — ky · GPT-6 Luna