Repository: nuxt/nuxt
Pull request #31379: perf(nuxt): use browser cache for payloads
Author: login: danielroe
Labels: name: 3.x
name: ⚡ performance
description: Performance degradation or optimization opportunity
Created: 2025-03-15T16:55:11Z | Merged: 2025-03-17T11:18:46Z

### 🔗 Linked issue

resolves https://github.com/nuxt/nuxt/issues/15438 (together with https://github.com/nuxt/nuxt/pull/31373)

### 📚 Description

this addresses a number of issues:

1. previously `preloadPayload` was entirely broken with JSON payloads (it was not internally used and seems not to have been used externally either as there was no bug report) and did not set the crossorigin attribute properly
2. previously the payload cache was never cleared and just increased in memory
3. previously on prefetch the payload was already loaded into memory, not just fetched

Instead, we now ~~hint to browser to prefetch a URL~~ we still import the URL but do not set it in memory (we will prefetch URL when we can also prefetch server components too). when we actually load it we force using browser cache (the query param busts this cache so it's safe to do). this allows the browser to safely clean up the cache when required; nuxt will refetch payloads in this case if needed.

this should _dramatically_ improve memory usage on large or content-driven websites.


Diff:
diff --git a/docs/2.guide/3.going-further/1.experimental-features.md b/docs/2.guide/3.going-further/1.experimental-features.md
index 1f7f33bf519e..9bf3c8f4c98f 100644
--- a/docs/2.guide/3.going-further/1.experimental-features.md
+++ b/docs/2.guide/3.going-further/1.experimental-features.md
@@ -514,3 +514,20 @@ class SomeClass {
 const value = new SomeClass().someMethod()
 // this will return 'decorated'
 ```
+
+## purgeCachedData
+
+Nuxt will automatically purge cached data from `useAsyncData` and `nuxtApp.static.data`. This helps prevent memory leaks
+and ensures fresh data is loaded when needed, but it is possible to disable it:
+
+```ts twoslash [nuxt.config.ts]
+export default defineNuxtConfig({
+  experimental: {
+    purgeCachedData: false
+  }
+})
+```
+
+::read-more{icon="i-simple-icons-github" color="gray" to="https://github.com/nuxt/nuxt/pull/31379" target="_blank"}
+See PR #31379 for implementation details.
+::
diff --git a/packages/nuxt/src/app/composables/payload.ts b/packages/nuxt/src/app/composables/payload.ts
index d16f10e4cd3a..cbdf3f36ac9b 100644
--- a/packages/nuxt/src/app/composables/payload.ts
+++ b/packages/nuxt/src/app/composables/payload.ts
@@ -19,35 +19,43 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
+  const shouldLoadPayload = await isPrerendered(url)
+  if (!shouldLoadPayload) {
+    return null
   }
-  cache[payloadURL] = isPrerendered(url).then((prerendered) => {
-    if (!prerendered) {
-      cache[payloadURL] = null
-      return null
-    }
-    return _importPayload(payloadURL).then((payload) => {
-      if (payload) { return payload }
-
-      delete cache[payloadURL]
-      return null
-    })
-  })
-  return cache[payloadURL]
+  const payloadURL = await _getPayloadURL(url, opts)
+  return await _importPayload(payloadURL) || null
+}
+let linkRelType: string | undefined
+function detectLinkRelType () {
+  if (import.meta.server) { return 'preload' }
+  if (linkRelType) { return linkRelType }
+  const relList = document.createElement('link').relList
+  linkRelType = relList && relList.supports && relList.supports('prefetch') ? 'prefetch' : 'preload'
+  return linkRelType
 }
 /** @since 3.0.0 */
 export function preloadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<void> {
   const nuxtApp = useNuxtApp()
   const promise = _getPayloadURL(url, opts).then((payloadURL) => {
-    nuxtApp.runWithContext(() => useHead({
-      link: [
-        { rel: 'modulepreload', href: payloadURL },
-      ],
-    }))
+    const link = renderJsonPayloads
+      ? { rel: detectLinkRelType(), as: 'fetch', crossorigin: 'anonymous', href: payloadURL } as const
+      : { rel: 'modulepreload', crossorigin: '', href: payloadURL } as const
+
+    if (import.meta.server) {
+      nuxtApp.runWithContext(() => useHead({ link: [link] }))
+    } else {
+      const linkEl = document.createElement('link')
+      for (const key of Object.keys(link) as Array<keyof typeof link>) {
+        linkEl[key === 'crossorigin' ? 'crossOrigin' : key] = link[key]!
+      }
+      document.head.appendChild(linkEl)
+      return new Promise<void>((resolve, reject) => {
+        linkEl.addEventListener('load', () => resolve())
+        linkEl.addEventListener('error', () => reject())
+      })
+    }
   })
   if (import.meta.server) {
     onServerPrefetch(() => promise)
@@ -73,7 +81,7 @@ async function _getPayloadURL (url: string, opts: LoadPayloadOptions = {}) {
 async function _importPayload (payloadURL: string) {
   if (import.meta.server || !payloadExtraction) { return null }
   const payloadPromise = renderJsonPayloads
-    ? fetch(payloadURL).then(res => res.text().then(parsePayload))
+    ? fetch(payloadURL, { cache: 'force-cache' }).then(res => res.text().then(parsePayload))
     : import(/* webpackIgnore: true */ /* @vite-ignore */ payloadURL).then(r => r.default || r)
 
   try {
diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts
index 7b6af5e1b1de..0318016dc6e4 100644
--- a/packages/nuxt/src/app/nuxt.ts
+++ b/packages/nuxt/src/app/nuxt.ts
@@ -150,8 +150,6 @@ interface _NuxtApp {
 
   /** @internal */
   _observer?: { observe: (element: Element, callback: () => void) => () => void }
-  /** @internal */
-  _payloadCache?: Record<string, Promise<Record<string, any>> | Record<string, any> | null>
 
   /** @internal */
   _appConfig: AppConfig
diff --git a/packages/nuxt/src/app/plugins/payload.client.ts b/packages/nuxt/src/app/plugins/payload.client.ts
index 48486c1a3ee9..0b5459adb2bb 100644
--- a/packages/nuxt/src/app/plugins/payload.client.ts
+++ b/packages/nuxt/src/app/plugins/payload.client.ts
@@ -3,8 +3,9 @@ import { loadPayload } from '../composables/payload'
 import { onNuxtReady } from '../composables/ready'
 import { useRouter } from '../composables/router'
 import { getAppManifest } from '../composables/manifest'
+
 // @ts-expect-error virtual file
-import { appManifest as isAppManifestEnabled } from '#build/nuxt.config.mjs'
+import { appManifest as isAppManifestEnabled, purgeCachedData } from '#build/nuxt.config.mjs'
 
 export default defineNuxtPlugin({
   name: 'nuxt:payload',
@@ -13,11 +14,22 @@ export default defineNuxtPlugin({
     if (import.meta.dev) { return }
 
     // Load payload after middleware & once final route is resolved
+    const staticKeysToRemove = new Set<string>()
     useRouter().beforeResolve(async (to, from) => {
       if (to.path === from.path) { return }
       const payload = await loadPayload(to.path)
       if (!payload) { return }
-      Object.assign(nuxtApp.static.data, payload.data)
+      for (const key of staticKeysToRemove) {
+        if (purgeCachedData) {
+          delete nuxtApp.static.data[key]
+        }
+      }
+      for (const key in payload.data) {
+        if (!(key in nuxtApp.static.data)) {
+          staticKeysToRemove.add(key)
+        }
+        nuxtApp.static.data[key] = payload.data[key]
+      }
     })
 
     onNuxtReady(() => {
@@ -25,7 +37,8 @@ export default defineNuxtPlugin({
       nuxtApp.hooks.hook('link:prefetch', async (url) => {
         const { hostname } = new URL(url, window.location.href)
         if (hostname === window.location.hostname) {
-          await loadPayload(url)
+          // TODO: use preloadPayload instead once we can support preloading islands too
+          await loadPayload(url).catch(() => { console.warn('[nuxt] Error preloading payload for', url) })
         }
       })
       if (isAppManifestEnabled && navigator.connection?.effectiveType !== 'slow-2g') {
diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts
index a53e4e1b1832..17d0677a83c8 100644
--- a/packages/nuxt/src/core/templates.ts
+++ b/packages/nuxt/src/core/templates.ts
@@ -570,6 +570,7 @@ export const nuxtConfigTemplate: NuxtTemplate = {
       `export const chunkErrorEvent = ${ctx.nuxt.options.experimental.emitRouteChunkError ? ctx.nuxt.options.builder === '@nuxt/vite-builder' ? '"vite:preloadError"' : '"nuxt:preloadError"' : 'false'}`,
       `export const crawlLinks = ${!!((ctx.nuxt as any)._nitro as Nitro).options.prerender.crawlLinks}`,
       `export const spaLoadingTemplateOutside = ${ctx.nuxt.options.experimental.spaLoadingTemplateLocation === 'body'}`,
+      `export const purgeCachedData = ${!!ctx.nuxt.options.experimental.purgeCachedData}`,
     ].join('\n\n')
   },
 }
diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts
index aef9df1d2877..dfcf189ee613 100644
--- a/packages/schema/src/config/experimental.ts
+++ b/packages/schema/src/config/experimental.ts
@@ -492,5 +492,30 @@ export default defineResolvers({
      * Disable resolving imports into Nuxt templates from the path of the module that added the template.
      */
     templateImportResolution: true,
+
+    /**
+     * Whether to clean up Nuxt static and asyncData caches on route navigation.
+     *
+     * Nuxt will automatically purge cached data from `useAsyncData` and `nuxtApp.static.data`. This helps prevent memory leaks
+     * and ensures fresh data is loaded when needed, but it is possible to disable it.
+     *
+     * @example
+     * ```ts
+     * // nuxt.config.ts
+     * export default defineNuxtConfig({
+     *   experimental: {
+     *     // Disable automatic cache cleanup (default is true)
+     *     purgeCachedData: false
+     *   }
+     * })
+     * ```
+     *
+     * @see [PR #31379](https://github.com/nuxt/nuxt/pull/31379)
+     */
+    purgeCachedData: {
+      $resolve: (val) => {
+        return typeof val === 'boolean' ? val : true
+      },
+    },
   },
 })
diff --git a/test/basic.test.ts b/test/basic.test.ts
index be977c9eb481..5a45ebcd4b49 100644
--- a/test/basic.test.ts
+++ b/test/basic.test.ts
@@ -2068,13 +2068,14 @@ describe.skipIf(isDev() || isWindows || !isRenderingJson)('prefetching', () => {
     await gotoPath(page, '/prefetch')
     await page.waitForLoadState('networkidle')
 
-    const snapshot = [...requests]
+    expect(requests.some(req => req.startsWith('/__nuxt_island/AsyncServerComponent'))).toBe(true)
+    requests.length = 0
     await page.click('[href="/prefetch/server-components"]')
     await page.waitForLoadState('networkidle')
 
     expect(await page.innerHTML('#async-server-component-count')).toBe('34')
 
-    expect(requests).toEqual(snapshot)
+    expect(requests.some(req => req.startsWith('/__nuxt_island/AsyncServerComponent'))).toBe(false)
     await page.close()
   })
 


Reviews:
user: login: TheAlexLichter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-15T17:24:09Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-15T17:42:19Z
user: login: huang-julien
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-16T22:34:00Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-16T23:29:08Z
user: login: huang-julien
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-16T23:30:45Z
user: login: TheAlexLichter
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-17T09:02:45Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/app/plugins/payload.client.ts (1)</summary><blockquote>

`38-39`: **Offer to finalise the TODO.**  
The comment suggests using `preloadPayload` once island preloading is supported. Are you open to me opening an issue or drafting a follow-up PR to address this?

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7ff19038dfe4b6403c6ecbd30997e36524b4c872 and d9ec3beef04d6e6553787f36539129b810eca943.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `packages/nuxt/src/app/plugins/payload.client.ts` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: codeql (javascript-typescript)
* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>packages/nuxt/src/app/plugins/payload.client.ts (4)</summary>

`6-6`: **No substantive change.**  
No content to review on this line.

---

`17-17`: **Neat solution for handling removable keys.**  
Using a `Set` to track keys destined for removal is concise and helps ensure they are cleaned up efficiently.

---

`22-24`: **Effective clean-up of stale data.**  
Removing keys from `nuxtApp.static.data` upon navigation is a valid way to prevent stale information from persisting.

---

`25-30`: **Verify logic for newly introduced data.**  
Any keys that were not previously in `nuxtApp.static.data` are self-flagged for future removal. Verify that we truly want to remove these new keys upon subsequent navigation, especially if they remain relevant across multiple routes.  

Would you like me to generate a script to confirm references to these keys in other routes?

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T10:03:29Z

Review comments:
diff_hunk: @@ -19,34 +19,22 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
path: packages/nuxt/src/app/composables/payload.ts
user: login: TheAlexLichter
body: Will this be part of a separate PR?
created_at: 2025-03-15T17:24:09Z
author_association: MEMBER
diff_hunk: @@ -19,34 +19,22 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
path: packages/nuxt/src/app/composables/payload.ts
user: login: danielroe
body: yes.

it's an existing todo that i forgot to write in previously (ie it's not changed by this pr) 
created_at: 2025-03-15T17:42:19Z
author_association: MEMBER
diff_hunk: @@ -19,35 +19,43 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
+  const shouldLoadPayload = await isPrerendered(url)
+  if (!shouldLoadPayload) {
+    return null
   }
-  cache[payloadURL] = isPrerendered(url).then((prerendered) => {
-    if (!prerendered) {
-      cache[payloadURL] = null
-      return null
-    }
-    return _importPayload(payloadURL).then((payload) => {
-      if (payload) { return payload }
-
-      delete cache[payloadURL]
-      return null
-    })
-  })
-  return cache[payloadURL]
+  const payloadURL = await _getPayloadURL(url, opts)
+  return await _importPayload(payloadURL) || null
+}
+let linkRelType: string | undefined
+function detectLinkRelType () {
path: packages/nuxt/src/app/composables/payload.ts
user: login: huang-julien
body: can this be run server side too ?
created_at: 2025-03-16T22:33:53Z
author_association: MEMBER
diff_hunk: @@ -19,35 +19,43 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
+  const shouldLoadPayload = await isPrerendered(url)
+  if (!shouldLoadPayload) {
+    return null
   }
-  cache[payloadURL] = isPrerendered(url).then((prerendered) => {
-    if (!prerendered) {
-      cache[payloadURL] = null
-      return null
-    }
-    return _importPayload(payloadURL).then((payload) => {
-      if (payload) { return payload }
-
-      delete cache[payloadURL]
-      return null
-    })
-  })
-  return cache[payloadURL]
+  const payloadURL = await _getPayloadURL(url, opts)
+  return await _importPayload(payloadURL) || null
+}
+let linkRelType: string | undefined
+function detectLinkRelType () {
path: packages/nuxt/src/app/composables/payload.ts
user: login: danielroe
body: yes. preloadPayload has server handling
created_at: 2025-03-16T23:29:08Z
author_association: MEMBER
diff_hunk: @@ -19,35 +19,43 @@ interface LoadPayloadOptions {
 /** @since 3.0.0 */
 export async function loadPayload (url: string, opts: LoadPayloadOptions = {}): Promise<Record<string, any> | null> {
   if (import.meta.server || !payloadExtraction) { return null }
-  const payloadURL = await _getPayloadURL(url, opts)
-  const nuxtApp = useNuxtApp()
-  const cache = nuxtApp._payloadCache ||= {}
-  if (payloadURL in cache) {
-    return cache[payloadURL] || null
+  // TODO: allow payload extraction for non-prerendered URLs
+  const shouldLoadPayload = await isPrerendered(url)
+  if (!shouldLoadPayload) {
+    return null
   }
-  cache[payloadURL] = isPrerendered(url).then((prerendered) => {
-    if (!prerendered) {
-      cache[payloadURL] = null
-      return null
-    }
-    return _importPayload(payloadURL).then((payload) => {
-      if (payload) { return payload }
-
-      delete cache[payloadURL]
-      return null
-    })
-  })
-  return cache[payloadURL]
+  const payloadURL = await _getPayloadURL(url, opts)
+  return await _importPayload(payloadURL) || null
+}
+let linkRelType: string | undefined
+function detectLinkRelType () {
path: packages/nuxt/src/app/composables/payload.ts
user: login: huang-julien
body: oh my bad, didn't see the `import.meta.server` flag
created_at: 2025-03-16T23:30:45Z
author_association: MEMBER

PR comments:
user: login: bolt-new-by-stackblitz[bot]
created_at: 2025-03-15T16:55:14Z
body: <a href="https://stackblitz.com/~/github.com/nuxt/nuxt/pull/31379"><img src="https://developer.stackblitz.com/img/review_pr_small.svg" alt="Review PR in StackBlitz Codeflow" align="left" width="103" height="20"></a> _Run & review this pull request in [StackBlitz Codeflow](https://stackblitz.com/~/github.com/nuxt/nuxt/pull/31379)._

author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-15T16:57:24Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes remove the caching mechanism from the `loadPayload` function, which now checks if a URL is prerendered before attempting to load its payload. The approach has been simplified to directly retrieve and import the payload when applicable. In the `preloadPayload` function, the link element logic has been modified to conditionally use either a preload or prefetch relation depending on a flag, with added event listeners for load and error states. Additionally, the `_importPayload` function now uses a fetch cache option of `'force-cache'. Internally, the `_payloadCache` property has been removed from the `_NuxtApp` interface, reflecting a change in the payload state management. A new hook in the Nuxt plugin clears static payload data once page rendering finishes. The test suite has also been updated to perform direct assertions on the requests array rather than relying on snapshot mechanisms. Furthermore, a new configuration option, `purgeCachedData`, has been introduced to manage cached data cleanup during route navigation.

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d9ec3beef04d6e6553787f36539129b810eca943 and 2e8f239c2bdee52abd15d60f4bbec22812cefe88.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `docs/2.guide/3.going-further/1.experimental-features.md` (1 hunks)
* `packages/nuxt/src/app/plugins/payload.client.ts` (2 hunks)
* `packages/nuxt/src/core/templates.ts` (1 hunks)
* `packages/schema/src/config/experimental.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* packages/nuxt/src/app/plugins/payload.client.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 LanguageTool</summary>

<details>
<summary>docs/2.guide/3.going-further/1.experimental-features.md</summary>

[uncategorized] ~530-~530: Loose punctuation mark.
Context: ...     purgeCachedData: false   } }) ```  ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)

---

[uncategorized] ~532-~532: Loose punctuation mark.
Context: ...e PR #31379 for implementation details. :: 

(UNLIKELY_OPENING_PUNCTUATION)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: codeql (actions)
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>docs/2.guide/3.going-further/1.experimental-features.md (1)</summary>

`517-533`: **Well-documented new experimental feature**

The addition of the `purgeCachedData` experimental feature is clearly documented, explaining its purpose of preventing memory leaks and ensuring fresh data is loaded when needed. The documentation follows the established pattern of other experimental features in this file, with a concise explanation, code example, and reference to the implementation PR.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 LanguageTool</summary>

[uncategorized] ~530-~530: Loose punctuation mark.
Context: ...     purgeCachedData: false   } }) ```  ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)

---

[uncategorized] ~532-~532: Loose punctuation mark.
Context: ...e PR #31379 for implementation details. :: 

(UNLIKELY_OPENING_PUNCTUATION)

</details>

</details>

</details>
<details>
<summary>packages/nuxt/src/core/templates.ts (1)</summary>

`573-573`: **Properly integrates the new configuration option**

The addition of the `purgeCachedData` export in the `nuxtConfigTemplate` correctly makes this setting available to the application. The value is appropriately coerced to a boolean using the double negation operator (`!!`), which ensures consistent typing.

</details>
<details>
<summary>packages/schema/src/config/experimental.ts (1)</summary>

`495-519`: **Comprehensive implementation of the new experimental feature**

The `purgeCachedData` feature is well-implemented with thorough documentation that explains its purpose, benefits, and configuration options. The JSDoc comments include a clear example of how to disable the feature and reference the PR for more details. The resolver function correctly handles different input types, defaulting to `true` which sensibly enables this memory optimization by default.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=nuxt/nuxt&utm_content=31379):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: pkg-pr-new[bot]
created_at: 2025-03-15T17:07:01Z
body: 
[Open in Stackblitz](https://pkg.pr.new/template/4058e185-87c5-4fd8-a15e-5cbc3aa03a81)


<details><summary><b>@nuxt/kit</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/kit@31379
```

</p></details>
      
    

<details><summary><b>nuxt</b></summary><p>

```
npm i https://pkg.pr.new/nuxt@31379
```

</p></details>
      
    

<details><summary><b>@nuxt/schema</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/schema@31379
```

</p></details>
      
    

<details><summary><b>@nuxt/rspack-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/rspack-builder@31379
```

</p></details>
      
    

<details><summary><b>@nuxt/vite-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/vite-builder@31379
```

</p></details>
      
    

<details><summary><b>@nuxt/webpack-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/webpack-builder@31379
```

</p></details>
      
    

_commit: <a href="https://github.com/nuxt/nuxt/runs/38879608156"><code>2e8f239</code></a>_

author_association: NONE
user: login: codspeed-hq[bot]
created_at: 2025-03-15T17:16:43Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_INSTRUMENTATION_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Performance Report](https://codspeed.io/nuxt/nuxt/branches/perf%2Fstatic-payloads)

### Merging #31379 will **not alter performance**

<sub>Comparing <code>perf/static-payloads</code> (2e8f239) with <code>main</code> (26ed789)</sub>



### Summary

`✅ 10` untouched benchmarks  




author_association: NONE
user: login: SoaresMG
created_at: 2025-03-20T17:07:01Z
body: When doing some performance analysis this previous cache variable used to be a hotspot for stuff hanging around forever.

However, I'm not understanding how this new behaviour will work with `sharedPrerenderData` which if I'm not mistaken is the experimental feature that shares payloads between requests.

We are now using `force-cache` but if I'm using SSG, how will this work out? Since node doesn't have that concept (or does it? 🤔)

If I have 100 pages using the same URL in a `useAsyncData` during SSG, will it share the same payload and still prevent 99 requests?
author_association: NONE
user: login: danielroe
created_at: 2025-03-20T20:35:21Z
body: this does not affect the sharedPrerenderData feature 
author_association: MEMBER
user: login: SoaresMG
created_at: 2025-03-21T18:09:15Z
body: Can confirm, works wonders!

On 24 websites using SSG with some reaching 3k pages (and most are pretty payload heavy) we had a huge memory decrease with 3.16.1 and the flag active.

On average it was around 2gb less, heaviest ones going from 9-10 to 7-8 while smaller ones also registering a 1-2gb decrease.

The only downside I noticed is that while memory decreased, generation time for all websites also increased by a max of 2-3 minutes, but it's weird because it's not correlated with website size (amount of routes), smaller websites had the same increase as some bigger ones, I need to investigate this further.

Overall great improvement!
author_association: NONE
user: login: mertgundoganx
created_at: 2025-06-19T15:02:07Z
body: if i dont want to use this with useAsyncData what should i do? any global settings?
author_association: NONE
user: login: danielroe
created_at: 2025-06-19T19:05:39Z
body: @mertgundoganx it is not configurable. 

if you don't want this, perhaps you could open a new issue and explain why not? do you understand what is happening and what happened before this pr?
author_association: MEMBER