nextjs - 💡(How to fix) Fix Dynamic Headers lead to Useless Cache [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#84414Fetched 2026-04-08 02:19:26
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
closed ×1commented ×1labeled ×1locked ×1

Fix Action

Fix / Workaround

Another idea, could be to extend the patched fetch API to allow for a user defined cache key function that has the same signature as-is today

  async generateCacheKey(
    url: string,
    init: RequestInit | Request = {}
  ): Promise<string>

Code Example

// w3c trace context headers can break request caching and deduplication
// so we remove them from the cache key
if ('traceparent' in headers) delete headers['traceparent']
if ('tracestate' in headers) delete headers['tracestate']

const cacheString = JSON.stringify([
  MAIN_KEY_PREFIX,
  this.fetchCacheKeyPrefix || '',
  url,
  init.method,
  headers,
  init.mode,
  init.redirect,
  init.credentials,
  init.referrer,
  init.referrerPolicy,
  init.integrity,
  init.cache,
  bodyChunks,
])

---

if (cacheKeyExcludedHeaders)) {
    cacheKeyExcludedHeaders.forEach((excludedHeader) => {
      if (excludedHeader in headers) {
        delete headers[excludedHeader];
      }
    });
  }

---

async generateCacheKey(
    url: string,
    init: RequestInit | Request = {}
  ): Promise<string>
RAW_BUFFERClick to expand / collapse

Issue

Our team recently introduced annotating all outbound requests (i.e. fetches) with a Correlation ID and have discovered that this breaks cache deduplication, effectively rendering it useless.

If we have multiple pods of our Next application and a user makes a request to /page1 which makes a fetch, the outbound request will have a Request header with correlation ID 123 and the result will be stored in cache (in our instances its shared cache in Redis, but it also applies to a singleton process with in memory cache). If another user, 2 seconds later, makes a request to /page1 Next will check to see if there is a result in cache before fetching from origin, but the correlation ID on that request might be 456 which means the cache key for these two requests are different and thus the fetch cache is rendered useless.

I found that the reason for this is that ALL headers are considered when generating the cache key per https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/incremental-cache/index.ts#L373-L392.

// w3c trace context headers can break request caching and deduplication
// so we remove them from the cache key
if ('traceparent' in headers) delete headers['traceparent']
if ('tracestate' in headers) delete headers['tracestate']

const cacheString = JSON.stringify([
  MAIN_KEY_PREFIX,
  this.fetchCacheKeyPrefix || '',
  url,
  init.method,
  headers,
  init.mode,
  init.redirect,
  init.credentials,
  init.referrer,
  init.referrerPolicy,
  init.integrity,
  init.cache,
  bodyChunks,
])

There are some recent commits that exclude traceparent and tracestate from consideration of the cache key and I want to take this a step further and allow users to define a set of headers that will be excluded. The reason for this is that there are MANY implementations of this type of trace ID / correlation ID header outside of the ones in w3c so let users decide which ones they feel are dynamic and wouldn't make two fetches be considered different. Another example might be requests that send along a Date header, those might not want to be considered 'different' in the cache, so users can specify that in some list of excluded headers.

Proposal

Yes, I am interested in contributing.

We would need to add this cacheKeyExcludedHeaders in next.config.js that accepts an array of strings and then in the incremental-cache.ts file we could update the code to do this before defining cacheString.

  if (cacheKeyExcludedHeaders)) {
    cacheKeyExcludedHeaders.forEach((excludedHeader) => {
      if (excludedHeader in headers) {
        delete headers[excludedHeader];
      }
    });
  }

Another idea, could be to extend the patched fetch API to allow for a user defined cache key function that has the same signature as-is today

  async generateCacheKey(
    url: string,
    init: RequestInit | Request = {}
  ): Promise<string>

Originally posted by @dylandignan in https://github.com/vercel/next.js/discussions/76875

extent analysis

TL;DR

To fix the cache deduplication issue caused by dynamic headers like Correlation ID, allow users to define excluded headers in next.config.js and update the incremental cache logic to ignore these headers when generating the cache key.

Guidance

  • Identify the dynamic headers that are causing the cache deduplication issue, such as Correlation ID or Date headers.
  • Introduce a cacheKeyExcludedHeaders option in next.config.js to allow users to specify an array of headers to exclude from the cache key generation.
  • Update the incremental-cache.ts file to remove the excluded headers from the headers object before generating the cache key.
  • Consider extending the patched fetch API to allow for a user-defined cache key function, providing more flexibility in cache key generation.

Example

// next.config.js
module.exports = {
  // ...
  cacheKeyExcludedHeaders: ['correlation-id', 'date'],
};

// incremental-cache.ts
if (cacheKeyExcludedHeaders) {
  cacheKeyExcludedHeaders.forEach((excludedHeader) => {
    if (excludedHeader in headers) {
      delete headers[excludedHeader];
    }
  });
}

Notes

The proposed solution assumes that the dynamic headers are known and can be excluded from the cache key generation. However, this might not cover all cases, and additional logic might be needed to handle unknown or unexpected headers.

Recommendation

Apply the proposed workaround by introducing the cacheKeyExcludedHeaders option and updating the incremental cache logic. This will provide a flexible solution for users to define which headers to exclude from the cache key generation, addressing the cache deduplication issue caused by dynamic headers.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - 💡(How to fix) Fix Dynamic Headers lead to Useless Cache [1 comments, 2 participants]