nitrojs / nitrojs/nitro

Netlify preset: defineCachedEventHandler doesn't emit Netlify-Vary: query, causing query-variant cache collapse

Open
#4,165 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug nuxt v2
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.