Ky instances collect request defaults so you can share a transport policy while keeping
different API clients independent. Use ky directly for one-off requests, ky.create()
for a new set of defaults, and ky.extend() when a client should inherit and modify another
client.
How the defaults compose
create() starts a new instance. It does not inherit defaults from the default instance or from
another client. extend() starts from its parent, then merges the options you provide. A function
form of extend() receives the parent options, so a child can derive a value such as a longer URL
prefix.
mermaidflowchart LR A["ky.create(defaults)"] --> B["base client"] B --> C["ky.extend(changes)"] C --> D["child client"] E["request options"] --> F["merged request"] B --> F D --> F
The instance exposes method shortcuts such as get() and post(). Each shortcut returns a
response promise with body methods such as .text() and .json(); the method shortcut supplies
the HTTP method while the instance supplies its defaults.
Create a shared client
Pass an Options object to create(). The following client gives every
relative request a base URL, a path prefix, a header, and a request hook. The trailing slash on
baseUrl keeps page-relative paths under /api/ when standard URL resolution applies.
tsimport ky from 'ky';
async function main(): Promise<void> {
const api = ky.create({
baseUrl: 'https://api.example.com/api/',
prefix: 'v1',
headers: {
accept: 'application/json',
},
hooks: {
beforeRequest: [({request}) => {
request.headers.set('x-client', 'web');
}],
},
retry: 2,
timeout: 10_000,
});
const response = await api.get('users/42');
console.log(response.url);
}
main();
The request uses the instance's defaults and resolves to a URL under the configured base URL and
prefix. The hook runs immediately before the request is sent, and retry and timeout apply to
requests made through this instance unless a request supplies different values.
Extend a client for a narrower API
Call extend() on the parent instance when a child shares the parent's policy. The function form
lets you read the parent options. This example adds users to the existing prefix and adds a
child-specific header without rebuilding the base client.
tsimport ky from 'ky';
async function main(): Promise<void> {
const api = ky.create({
baseUrl: 'https://api.example.com/api/',
prefix: 'v1',
headers: {
accept: 'application/json',
},
});
const usersApi = api.extend(parentOptions => ({
prefix: `${parentOptions.prefix}/users`,
headers: {
'x-resource': 'users',
},
}));
const response = await usersApi.get('42');
console.log(response.url);
}
main();
usersApi keeps the base URL and inherited accept header, adds the resource header, and sends
GET /api/v1/users/42. Calling api.get('version') still uses the parent prefix and does not use
the child prefix.
Know what is merged
By default, extend() deep-merges options. Headers merge, search parameters accumulate, and hook
arrays append. This is useful for layering policy, but it is not a replacement operation.
| Option | Type | Default | Effect when extended |
|---|---|---|---|
baseUrl | string | URL | — | Resolves relative input after prefix is applied. An absolute input bypasses it. |
prefix | string | URL | — | Joins before URL resolution; a slash at the join boundary is normalized. |
headers | header object | — | Merges with parent headers. |
hooks | Hooks | — | Appends hook arrays by default. |
searchParams | SearchParamsOption | '' | Accumulates with the parent's search parameters. |
retry | RetryOptions | number | — | Supplies retry policy for requests from the instance. |
timeout | number | false | — | Sets the per-attempt response timeout in milliseconds. |
Use replaceOption when a child must replace a merged value rather than add to it.
For example, this child runs only its own beforeRequest hook:
tsimport ky, {replaceOption} from 'ky';
async function main(): Promise<void> {
const api = ky.create({
hooks: {
beforeRequest: [() => {
console.log('parent hook');
}],
},
});
const child = api.extend({
hooks: replaceOption({
beforeRequest: [() => {
console.log('child hook');
}],
}),
});
await child.get('https://example.com');
}
main();
The child hook replaces the parent's beforeRequest array. The same marker can replace other
deep-merged values, including headers, search parameters, context, and signals.
Choose baseUrl or prefix
Use baseUrl in most cases. It follows standard URL resolution: an input beginning with /
starts at the origin root, so it can override a path in the base URL. Use prefix when an
origin-relative input such as /users must be treated as page-relative and appended to the
prefix. The prefix is joined before baseUrl resolves the resulting input.
For a base URL with a path, include its trailing / when you want users and ./users to extend
that path rather than replace its last segment. A Request input bypasses both baseUrl and
prefix; searchParams still applies.
Related
Options— request and instance options.ResponsePromise— body methods returned by an instance request.- Shared clients and URL defaults — the warning about inherited headers, search parameters, and hooks.
Was this page helpful?