Netlify preset: defineCachedEventHandler doesn't emit Netlify-Vary: query, causing query-variant cache collapse
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 11.2k
- Forks
- 899
- Avg merge
- 2d 24m
- Merged PRs (30d)
- 40
Description
Environment
nitro v2, using netlify-edge preset.
The issue should also happen with netlify functions.
Reproduction
I spotted the bug using @nuxt/icon but the issue is broader.
@nuxt/icon registers /api/_nuxt_icon/[collection].json using:
defineCachedEventHandler(handler, {
getKey(event) {
const icons = String(getQuery(event).icons || "");
return `${collection}_${icons.split(",")[0]}_${icons.length}_${hash(icons)}`;
},
swr: true,
maxAge: 60 * 60 * 24 * 7,
});
The handler returns different JSON depending on the ?icons= query param. Nitro emits:
cache-control: s-maxage=604800, stale-while-revalidate
Netlify CDN caches this. The next request to the same path with a different ?icons= value gets the cached response from the first request — wrong icons.
Describe the bug
When using the Netlify preset, defineCachedEventHandler with a query-based getKey emits cache-control: s-maxage=..., stale-while-revalidate — which Netlify CDN honours by caching the response. But because no Netlify-Vary: query header is present, the CDN collapses all query string variants into a single cache entry, serving the first-cached response for every subsequent variant.
Nitro's server-side cache works correctly (it keys by the query-derived value). The CDN layer silently breaks it.
I managed to work around the issue by adding the netlify-vary header manually in Nuxt's routeRules:
// nuxt.config.ts
routeRules: {
'/api/_nuxt_icon/*': {
headers: { 'Netlify-Vary': 'query' },
},
}
Additional context
No response
Logs
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the Netlify preset handling for defineCachedEventHandler and how response headers are generated. Reproduce the issue with two query-string variants, then verify that the Netlify-Vary: query header is emitted and that a regression test covers distinct cached responses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cloud
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100