ky
Tiny and elegant HTTP client based on the Fetch API
Install
bashnpm install ky
On their own pages
HooksHTTPError: Error thrown when the response has a non-2xx status code andthrowHttpErrorsis enabled.KyRequestNormalizedOptions: Normalized options passed to thefetchcall and hooks.Options: Options are the same aswindow.fetch, except for the KyOptionsResponsePromiseRetryOptions
Functions
isForceRetryError
Type guard to check if an error is a ForceRetryError.
tsfunction isForceRetryError(error: unknown): error is ForceRetryError
Parameters
error: The error to check
Returns true if the error is a ForceRetryError, false otherwise
Example
import ky, {isForceRetryError} from 'ky'; const api = ky.extend({ hooks: { beforeRetry: [ ({error, retryCount}) => { if (isForceRetryError(error)) { console.log(`Forced retry #${retryCount}: ${error.code}`); } } ] } });
isHTTPError
Type guard to check if an error is an HTTPError.
tsfunction isHTTPError<T = unknown>(error: unknown): error is HTTPError<T>
Parameters
error: The error to check
Returns true if the error is an HTTPError, false otherwise
Example
import ky, {isHTTPError} from 'ky'; try { const response = await ky.get('/api/data'); } catch (error) { if (isHTTPError(error)) { console.log('HTTP error status:', error.response.status); } }
isKyError
Type guard to check if an error is a KyError.
Note: SchemaValidationError is intentionally not considered a Ky error. KyError covers failures in Ky's HTTP lifecycle (bad status, timeout, retry), while schema validation errors originate from the user-provided schema, not from Ky itself.
tsfunction isKyError(error: unknown): error is KyError
Parameters
error: The error to check
Returns true if the error is a Ky error, false otherwise
Example
import ky, {isKyError} from 'ky'; try { const response = await ky.get('/api/data'); } catch (error) { if (isKyError(error)) { // Handle Ky-specific errors console.log('Ky error occurred:', error.message); } else { // Handle other errors console.log('Unknown error:', error); } }
isNetworkError
Type guard to check if an error is a NetworkError.
tsfunction isNetworkError(error: unknown): error is NetworkError
Parameters
error: The error to check
Returns true if the error is a NetworkError, false otherwise
Example
import ky, {isNetworkError} from 'ky'; try { const response = await ky.get('/api/data'); } catch (error) { if (isNetworkError(error)) { console.log('Network error:', error.request.url); } }
isResponseSizeError
Not released yet. It is in the source, not in the latest release on npm.
Type guard to check if an error is a ResponseSizeError.
tsfunction isResponseSizeError(error: unknown): error is ResponseSizeError
Parameters
error: The error to check
Returns true if the error is a ResponseSizeError, false otherwise
Example
import ky, {isResponseSizeError} from 'ky'; try { await ky('https://example.com/data', {maxResponseSize: 1024}).json(); } catch (error) { if (isResponseSizeError(error)) { console.log(`Response exceeded ${error.maxResponseSize} bytes`); } }
isTimeoutError
Type guard to check if an error is a TimeoutError.
tsfunction isTimeoutError(error: unknown): error is TimeoutError
Parameters
error: The error to check
Returns true if the error is a TimeoutError, false otherwise
Example
import ky, {isTimeoutError} from 'ky'; try { const response = await ky.get('/api/data', { timeout: 1000 }); } catch (error) { if (isTimeoutError(error)) { console.log('Request timed out:', error.request.url); } }
Classes
ForceRetryError
Error used to signal a forced retry from afterResponse hooks.
This is thrown when ky.retry() is returned from an afterResponse hook. It is observable in beforeRetry and beforeError hooks via the isForceRetryError() type guard.
tsclass ForceRetryError extends KyError
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'ForceRetryError' | ||
customDelay | number | undefined | ||
code | string | undefined | ||
customRequest | Request | undefined | ||
message | string | ||
stack? | string |
Methods
constructor(options?: ForceRetryOptions)
KyError
Base class for all Ky-specific errors. HTTPError, NetworkError, TimeoutError, ResponseSizeError, and ForceRetryError extend this class.
You can use instanceof KyError to check if an error originated from Ky, or use the isKyError() type guard for cross-realm compatibility and TypeScript type narrowing.
Note: SchemaValidationError is intentionally not considered a Ky error. KyError covers failures in Ky's HTTP lifecycle (bad status, timeout, retry), while schema validation errors originate from the user-provided schema, not from Ky itself.
tsclass KyError extends Error
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'KyError' | ||
message | string | ||
stack? | string |
Methods
get isKyError(): true
NetworkError
Error thrown when a network error occurs during the request (e.g., DNS failure, connection refused, offline). It has a request property with the Request object. The original error is available via the standard cause property.
Network errors are automatically retried (for retriable methods). A connection that drops while a Ky shortcut method like .json() is reading the response body is also wrapped in NetworkError, but it is not retried because the response has already been received.
Note: Network errors are detected using runtime-specific heuristics. Unrecognized runtimes may produce errors that are not wrapped in NetworkError. Use the shouldRetry option to handle such cases.
tsclass NetworkError extends KyError
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'NetworkError' | ||
request | KyRequest | ||
message | string | ||
stack? | string |
Methods
constructor(request: Request, options?: {cause?: Error | undefined})
ResponseSizeError
Not released yet. It is in the source, not in the latest release on npm.
Error thrown when the response body exceeds maxResponseSize. It has a request property with the Request object and a maxResponseSize property with the configured limit in bytes.
tsclass ResponseSizeError extends KyError
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'ResponseSizeError' | ||
request | KyRequest | ||
maxResponseSize | number | ||
message | string | ||
stack? | string |
Methods
constructor(request: Request, maxResponseSize: number)
Example
import ky, {isResponseSizeError} from 'ky'; try { await ky('https://example.com/data', {maxResponseSize: 1024}).json(); } catch (error) { if (isResponseSizeError(error)) { console.log(`Response exceeded ${error.maxResponseSize} bytes`); } }
SchemaValidationError
The error thrown when Standard Schema validation fails in .json(schema). It has an issues property with the validation issues from the schema.
This error intentionally does not extend KyError because it does not represent a failure in Ky's HTTP lifecycle. The request succeeded; the user's schema rejected the data. As such, it is not matched by isKyError().
tsclass SchemaValidationError extends Error
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'SchemaValidationError' | ||
issues | readonly StandardSchemaV1Issue[] | ||
message | string | ||
stack? | string |
Methods
constructor(issues: readonly StandardSchemaV1Issue[])
Example
import ky, {SchemaValidationError} from 'ky'; import {z} from 'zod'; const userSchema = z.object({name: z.string()}); try { const user = await ky('/api/user').json(userSchema); console.log(user.name); } catch (error) { if (error instanceof SchemaValidationError) { console.error(error.issues); } }
TimeoutError
Error thrown when the request times out. It has a request property with the Request object.
tsclass TimeoutError extends KyError
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | 'TimeoutError' | ||
request | KyRequest | ||
message | string | ||
stack? | string |
Methods
constructor(request: Request)
Constants
default
The package's default export: import it under a name of your own, import ky from 'ky'.
tsdeclare const ky: KyInstance
export default ky
replaceOption
Wraps a value so that ky.extend() will replace the parent value instead of merging with it. Works with hooks, headers, search parameters, context, and any other deep-merged option.
By default, .extend() deep-merges options with the parent instance: hooks get appended, headers get merged, and search parameters get accumulated. Use replaceOption when you want to fully replace a merged property instead.
tsconst replaceOption: <T>(value: T) => T
Example
import ky, {replaceOption} from 'ky'; const base = ky.create({ hooks: {beforeRequest: [addAuth, addTracking]}, }); // Replaces instead of appending const extended = base.extend({ hooks: replaceOption({beforeRequest: [onlyThis]}), }); // hooks.beforeRequest is now [onlyThis], not [addAuth, addTracking, onlyThis]
Types
AfterResponseHook
tstype AfterResponseHook = (state: AfterResponseState) => Response | RetryMarker | void | Promise<Response | RetryMarker | void>;
AfterResponseState
tstype AfterResponseState = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
request | KyRequest | ||
options | Readonly<NormalizedOptions> | ||
response | KyResponse | ||
retryCount | number | The number of retries attempted. 0 for the initial request, increments with each retry. |
BeforeErrorHook
tstype BeforeErrorHook = (state: BeforeErrorState) => Error | Promise<Error>;
BeforeErrorState
tstype BeforeErrorState = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
request | KyRequest | ||
options | Readonly<NormalizedOptions> | ||
error | Error | ||
retryCount | number | The number of retries attempted. 0 for the initial request, increments with each retry. |
BeforeRequestHook
tstype BeforeRequestHook = (state: BeforeRequestState) => Request | Response | void | Promise<Request | Response | void>;
BeforeRequestState
tstype BeforeRequestState = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
request | KyRequest | ||
options | Readonly<NormalizedOptions> | ||
retryCount | 0 | The number of retries attempted. Always 0, since beforeRequest hooks run once before retry handling begins. |
BeforeRetryHook
tstype BeforeRetryHook = (state: BeforeRetryState) => Request | Response | typeof stop | void | Promise<Request | Response | typeof stop | void>;
BeforeRetryState
tstype BeforeRetryState = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
request | KyRequest | ||
options | Readonly<NormalizedOptions> | ||
error | Error | ||
retryCount | number | The number of retries attempted. Always >= 1, since this hook is only called during retries, not on the initial request. |
InitHook
This hook enables you to modify the options before they are used to construct the request. The hook function receives the mutable options object and can modify it in place. You could, for example, modify searchParams, headers, or json here. The headers option is always a plain object with lowercase names, where a header removed with undefined keeps an undefined value.
Unlike other hooks, init hooks are synchronous. Any error thrown will propagate synchronously and will not be caught by beforeError hooks.
tstype InitHook = (options: InitOptions) => void;
Example
import ky from 'ky'; const api = ky.extend({ hooks: { init: [ options => { options.searchParams = {apiKey: getApiKey()}; }, ], }, }); const response = await api.get('https://example.com/api/users'); // URL: https://example.com/api/users?apiKey=123
Input
tstype Input = string | URL | Request;
Members
toString(): string— Returns a string representation of a string.valueOf(): string— Returns the primitive value of the specified object.
KyInstance
tstype KyInstance = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
get | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'get'}. | |
post | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'post'}. | |
put | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'put'}. | |
delete | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'delete'}. | |
patch | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'patch'}. | |
head | (url: Input, options?: Options) => ResponsePromise | Fetch the given url using the option {method: 'head'}. | |
query | <T>(url: Input, options?: Options) => ResponsePromise<T> | Fetch the given url using the option {method: 'query'}. | |
create | (defaultOptions?: Options) => KyInstance | Create a new Ky instance with complete new defaults, without inheriting from any parent instance. | |
extend | (defaultOptions: Options | ((parentOptions: Options) => Options)) => KyInstance | Create a new Ky instance with some defaults overridden with your own. | |
stop | typeof stop | A Symbol that can be returned by a beforeRetry hook to stop the retry. This will also short circuit the remaining beforeRetry hooks. | |
retry | typeof retry | Force a retry from an afterResponse hook. |
KyResponse
tstype KyResponse<T = unknown> = {
clone: () => KyResponse<T>;
json: <J = T>() => Promise<J>;
} & Response;
Properties
| Name | Type | Default | Description |
|---|---|---|---|
clone | () => KyResponse<T> | ||
json | <J = T>() => Promise<J> | ||
headers | Headers | The headers read-only property of the with the response. | |
ok | boolean | The ok read-only property of the Response interface contains a Boolean stating whether the response was successful (status in the range 200-299) or not. | |
redirected | boolean | The redirected read-only property of the Response interface indicates whether or not the response is the result of a request you made which was redirected. | |
status | number | The status read-only property of the Response interface contains the HTTP status codes of the response. | |
statusText | string | The statusText read-only property of the Response interface contains the status message corresponding to the HTTP status code in Response.status. | |
type | ResponseType | The type read-only property of the Response interface contains the type of the response. | |
url | string | The url read-only property of the Response interface contains the URL of the response. | |
body | ReadableStream<Uint8Array<ArrayBuffer>> | null | MDN Reference | |
bodyUsed | boolean | MDN Reference |
Members
arrayBuffer(): Promise<ArrayBuffer>— MDN Referenceblob(): Promise<Blob>— MDN Referencebytes(): Promise<Uint8Array<ArrayBuffer>>— MDN ReferenceformData(): Promise<FormData>— MDN Referencetext(): Promise<string>— MDN Reference
Progress
tstype Progress = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
percent | number | A number between 0 and 1 representing the progress percentage. | |
transferredBytes | number | The number of bytes transferred so far. | |
totalBytes | number | The total number of bytes to be transferred. This is an estimate and may be 0 for an empty transfer or when the total size cannot be determined. |
SearchParamsOption
tstype SearchParamsOption =
| Exclude<SearchParamsInit, string[][]>
| Record<string, string | number | boolean | undefined>
| Array<Array<string | number | boolean>>
| ReadonlyArray<ReadonlyArray<string | number | boolean>>;
Members
toString(): string— Returns a string representation of a string.valueOf(): string— Returns the primitive value of the specified object.
ShouldRetryState
tstype ShouldRetryState = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
error | Error | The error that caused the request to fail. | |
retryCount | number | The number of retries attempted. Starts at 1 for the first retry. |
StandardSchemaV1
tstype StandardSchemaV1<InputType = unknown, OutputType = InputType> = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
'~standard' | { readonly version: 1; readonly vendor: string; readonly validate: ( value: unknown, options?: StandardSchemaV1Options, ) => StandardSchemaV1Result<OutputType> | Promise<StandardSchemaV1Result<OutputType>>; readonly types?: StandardSchemaV1Types<InputType, OutputType> | undefined; } | ||
'~standard' | { readonly version: 1; readonly vendor: string; readonly validate: ( value: unknown, options?: StandardSchemaV1Options, ) => StandardSchemaV1Result<OutputType> | Promise<StandardSchemaV1Result<OutputType>>; readonly types?: StandardSchemaV1Types<InputType, OutputType> | undefined; } |
StandardSchemaV1InferOutput
tstype StandardSchemaV1InferOutput<Schema extends StandardSchemaV1> = Schema['~standard'] extends {
readonly types: StandardSchemaV1Types<unknown, infer OutputType>;
}
? OutputType
: Extract<
Awaited<ReturnType<Schema['~standard']['validate']>>,
StandardSchemaV1SuccessResult<unknown>
> extends StandardSchemaV1SuccessResult<infer OutputType>
? OutputType
: unknown;
StandardSchemaV1Issue
tstype StandardSchemaV1Issue = { … }
Properties
| Name | Type | Default | Description |
|---|---|---|---|
message | string | ||
path? | ReadonlyArray<PropertyKey | {readonly key: PropertyKey}> | undefined |
Was this page helpful?