# Cookies

> 

**By default, no cookies take part in caching — in either direction.** This is a secure default:

- The `Cookie` request header is stripped before your handler runs, so the handler can't produce cookie-specific output that then gets cached and served to someone else.
- Cookies never vary the cache key.
- Any `Set-Cookie` your handler sets is removed before the response is cached or returned.

Together these keep a per-request cookie (such as a session id) from ever reaching another visitor — whether through a later cache hit or a concurrent request that is served the same cached response.

```ts
const page = defineCachedHandler(
  async (event) => {
    event.req.headers.get("cookie"); // always null for cached GET/HEAD requests
    return new Response(await renderPage(), {
      headers: { "content-type": "text/html" },
    });
  },
  { maxAge: 60 },
);
```

<note>

This only applies to cacheable requests (`GET` / `HEAD`). Methods that bypass the cache entirely (`POST`, `PUT`, …) reach the handler with the request untouched — cookies, headers, query, and body included — and their `Set-Cookie` is passed straight through.

</note>

## Allowing specific cookies

Set `allowCookies` to an allowlist of cookie names to opt specific cookies back in. For those cookies only:

- they stay in the `Cookie` header your handler sees,
- they vary the cache key (sorted and order-independent, like [`allowQuery`](/guide/query-params), so only that subset is part of the key — not the entire raw `Cookie` header),
- a matching `Set-Cookie` is allowed to be cached and returned.

Every other cookie is still stripped in both directions, and the rest of the response is cached as usual.

```ts
const page = defineCachedHandler(myHandler, {
  maxAge: 300,
  allowCookies: ["theme"], // theme=dark and theme=light cache separately; every other cookie is ignored
});
```

Cookie names are **case-sensitive**. `allowCookies` supersedes `varies: ["cookie"]` — set the allowlist and drop the coarse `varies` entry.

## Caveats

- **Custom getKey.** As with `allowQuery`, a custom `getKey` controls the cache key entirely, so allowlisted cookies no longer vary it automatically. If your handler's output depends on a cookie, incorporate it into `getKey` yourself. (The handler-visible `Cookie` header is still filtered to the allowlist regardless.)
- **Allowlisted cookies are shared — keep them cache-safe.** An allowlisted cookie is part of the cache: its value varies the key, and its `Set-Cookie` is cached and replayed to every visitor that resolves to the same key (concurrent requests are served a single shared response). Only allowlist cookies whose value is safe to share across everyone who shares that key — a `theme` or `locale` preference that is genuinely *part of* the key.

<caution>

**Never allowlist a per-user secret such as a session id.** Because a response is shared across everyone with the same cache key, that one value would leak between users. A handler that *mints* a per-request cookie (e.g. starting an anonymous session with a fresh `Set-Cookie`) must give each user a distinct entry via a user-specific `getKey` / `varies` — otherwise don't cache it. With no `allowCookies`, such a cookie is simply stripped, so the default never leaks; this only matters once you opt a cookie back in.

</caution>
