From d61824055fb0bafe3790d9d5e2f38b090963f82c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 19 Jun 2026 17:05:48 +0000 Subject: [PATCH 1/2] docs(Suspense): warn against module-level cache in SSR Add a Pitfall on the Suspense reference page explaining that the hidden data.js cache must not be copied into server environments like Next.js, where module-level state can leak data across requests. Clarify the data.js comment in all Suspense examples accordingly. Fixes reactjs/react.dev#8134 --- src/content/reference/react/Suspense.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index ec62d2424de..bfbfd1d2096 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -79,6 +79,12 @@ React will display your loading fallback until all In the example below, the `Albums` component *suspends* while fetching the list of albums. Until it's ready to render, React switches the closest Suspense boundary above to show the fallback--your `Loading` component. Then, when the data loads, React hides the `Loading` fallback and renders the `Albums` component with data. + + +Do not use a module-level cache like the one in `data.js` below in server environments such as Next.js. Module-level state persists across requests and can leak data between users. Use your framework's built-in caching, [`cache`](/reference/react/cache) in Server Components, or scope caches per request (for example, with a Context and `useRef`). + + + ```js src/App.js hidden @@ -148,6 +154,8 @@ export default function Albums({ artistId }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -606,6 +614,8 @@ export default function Albums({ artistId }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -868,6 +878,8 @@ export default function Albums({ artistId }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -1052,6 +1064,8 @@ export default function SearchResults({ query }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -1236,6 +1250,8 @@ export default function SearchResults({ query }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -1495,6 +1511,8 @@ export default function Panel({ children }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -1807,6 +1825,8 @@ export default function Panel({ children }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); @@ -2118,6 +2138,8 @@ export default function Panel({ children }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map(); From b6d9a963f6e8416bf434418b98a8234a5d41dc5f Mon Sep 17 00:00:00 2001 From: Camron Farjami <83742449+LuxologyGG@users.noreply.github.com> Date: Fri, 25 Sep 2026 15:06:53 -0400 Subject: [PATCH 2/2] docs(Suspense): add module-level cache warning to remaining data.js demo One hidden data.js Sandpack block was missing the same client-only demo warning already present on the other eight caches. --- src/content/reference/react/Suspense.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index bfbfd1d2096..412cdc5ec46 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -324,6 +324,8 @@ export default function EffectAlbums({ artistId }) { // Note: the way you would do data fetching depends on // the framework that you use together with Suspense. // Normally, the caching logic would be inside a framework. +// This module-level cache is only suitable for this client-only demo. +// Do not copy it into server environments. let cache = new Map();