Use ky to resolve endpoint paths against an API base, prepend a path when leading slashes must append, and merge query parameters into the outgoing URL. Ky builds on Fetch: you pass a string, URL, or Request and receive a response.
The samples run in a browser or Node.js with native Fetch support. They use absolute API addresses so URL construction also works on the server. Replace https://api.example.com with your API's origin; inspect the outgoing URLs in the console rather than relying on the service to echo them.
1. Resolve paths with baseUrl
Use baseUrl for standard URL resolution. Give a base path a trailing slash and pass a page-relative input such as 'users' to extend that path. Create an instance with the base as a default, then make requests through it:
tsimport ky from 'ky';
const api = ky.create({
baseUrl: 'https://api.example.com/v1/',
hooks: {
beforeRequest: [({request}) => {
console.log('Outgoing URL:', request.url);
}],
},
});
async function main() {
await api.get('users');
await api.get('/users');
}
main().catch(console.error);
The first call requests /v1/users; the second requests /users at the same origin. Each awaited call returns a response. The hook logs the constructed request URL before Ky sends it.
The input's leading slash means origin-root, not “append to the base.” A base without a trailing slash also changes how page-relative inputs resolve:
baseUrl | Input | Destination |
|---|---|---|
https://api.example.com/v1/ | users | https://api.example.com/v1/users |
https://api.example.com/v1/ | /users | https://api.example.com/users |
https://api.example.com/v1 | users | https://api.example.com/users |
An absolute input bypasses baseUrl. For example, with no prefix, 'https://other.example.com/users' stays at that address.
2. Append leading-slash inputs with prefix
Prefer baseUrl in most cases because it follows web standards. Use prefix when inputs such as /users must append to an API path instead of discarding it.
Ky joins prefix and the string input first, trimming trailing slashes from the prefix and leading slashes from the input at the join boundary. It then resolves the joined result against baseUrl, if present.
tsimport ky from 'ky';
const api = ky.create({
baseUrl: 'https://api.example.com/',
prefix: 'v1',
hooks: {
beforeRequest: [({request}) => {
console.log('Outgoing URL:', request.url);
}],
},
});
async function main() {
await api.get('users');
await api.get('/users');
}
main().catch(console.error);
Both calls request https://api.example.com/v1/users. A trailing slash on prefix is optional. Unlike baseUrl, prefix does string joining even when the string input contains an absolute URL; do not use it as an absolute-URL fallback.
3. Merge query parameters, including on a Request
Pass searchParams to add query parameters without building a query string yourself. Existing input parameters remain, and new values append rather than replace existing values with the same name. Use an object value of undefined to delete a parameter.
A Request input ignores baseUrl and prefix, but searchParams still applies:
tsimport ky from 'ky';
const request = new Request(
'https://api.example.com/users?role=reader&debug=true',
);
async function main() {
await ky.get(request, {
baseUrl: 'https://other.example.com/',
prefix: 'v1',
searchParams: {
page: 2,
active: true,
debug: undefined,
},
hooks: {
beforeRequest: [({request: outgoingRequest}) => {
console.log('Outgoing URL:', outgoingRequest.url);
}],
},
});
}
main().catch(console.error);
The outgoing URL stays at https://api.example.com/users. It retains role=reader, adds page=2 and active=true, and removes debug. The request does not move to other.example.com or acquire a /v1/ path.
You can also pass a query string, a URLSearchParams instance, or an array of key-value pairs. For example, repeated keys represent multiple values; adding another role does not erase the input's role=reader.
Options that matter
These fields belong to Options.
| Option | Type | Default | What it does |
|---|---|---|---|
baseUrl | string | URL | undefined | Resolves relative string inputs after prefix joining; absolute inputs bypass it. |
prefix | string | URL | '' | Prepends to string inputs, normalizing slashes at the join boundary. |
searchParams | Query string, object, key-value pairs, or URLSearchParams | '' | Merges query parameters into the input URL; object values of undefined delete keys. |
Server-side and input pitfalls
- Server-side requests require an absolute URL. Use an absolute
baseUrl, as above, rather than a browser-relative base such as/api/. In browsers, a relative base resolves against the environment's base URL, such asdocument.baseURI. - To extend a base path, keep its trailing slash and omit the input's leading slash. Use
prefixinstead when leading-slash inputs must append. prefixonly affects string inputs. Construct aURLorRequestwith its intended destination before passing it to Ky; neither receives prefix joining, and aRequestalso ignoresbaseUrl.
Related
- Instances and defaults — share URL options across requests.
- Request lifecycle — inspect or modify requests with hooks.
- Handle request errors — handle failures after constructing the URL.
Was this page helpful?