# Add request headers

Use a per-request `headers` option for one-off values, or add a `beforeRequest` hook to a [`ky`](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky#default) instance to attach shared headers to its requests.

## When to use each approach

Set headers on the request when a value applies only to that call. Put a header in an instance's request hook when the same value belongs on every request made through that instance, such as an application identifier.

## Set headers for one request

Pass a plain object as `headers` in the request options. The header is sent with this request; other calls made through `ky` do not inherit it.

```ts
import ky from 'ky';

async function loadProfile(): Promise<void> {
	const response = await ky.get('https://api.example.com/v1/profile', {
		headers: {
			'x-request-id': 'profile-view-42',
		},
	});

	const body = await response.text();
	console.log(body);
}

void loadProfile();
```

The request carries `x-request-id: profile-view-42`. In a browser, inspect the request's Headers in the Network panel to see the header that was sent. The call returns a response promise; here, `.text()` reads its response body.

## Add a shared header with a request hook

Create an instance with `extend()` and use its `beforeRequest` hook to modify the outgoing request. The hook receives the request, so set the header on `request.headers`.

```ts
import ky from 'ky';

const api = ky.extend({
	hooks: {
		beforeRequest: [
			({request}) => {
				request.headers.set('x-client-id', 'web-dashboard');
			},
		],
	},
});

async function loadProfile(): Promise<void> {
	const response = await api.get('https://api.example.com/v1/profile');

	const body = await response.text();
	console.log(body);
}

void loadProfile();
```

Requests made through `api` carry `x-client-id: web-dashboard`; calls through the default `ky` instance do not use this hook. The hook runs once before retry handling begins, and the response promise still gives you the response to read.

## Options that matter

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| [`Options`](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-options#options) `headers` | `Options['headers']` | — | Sets HTTP headers for an individual request or as an instance default. |
| `hooks.beforeRequest` | [`Hooks`](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-hooks#hooks)`['beforeRequest']` | `[]` | Runs before the request is sent; use its `request` argument to set shared headers. |

## Pitfalls

- A `beforeRequest` hook runs once with `retryCount` equal to `0`; it does not run again for a retry. Use the retry lifecycle when a header needs to change before a retry.
- An error thrown by a `beforeRequest` hook is fatal and does not trigger Ky's retry logic.
- The `json` option sets `Content-Type` to `application/json` unless your request `headers` option sets `Content-Type` itself.

## Related

- [Instances and defaults](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/instances-and-defaults)
- [The request lifecycle](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/the-request-lifecycle)
- [Send and read JSON](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/send-and-read-json)
- [Ky options](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-options)
