Cache components does not work on dynamic segments when localized
Link to the code that reproduces this issue
https://github.com/maxscn/intlayer-cache-components
To Reproduce
- Start the dev server.
- Go to /en/static (cached) and then /en/static/1 (not cached)
- Go to /static (cached) and then /static/1 (cached)
Current vs. Expected behavior
Following the steps, I expected the localized content to work exactly as the non-localized content. The locale is known at build time hence it should be possible to cache even the localized pages.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.1.0: Mon Oct 20 19:34:03 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8112
Available memory (MB): 16384
Available CPU cores: 8
Binaries:
Node: 22.16.0
npm: 10.9.2
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 16.0.7 // Latest available version is detected (16.0.7).
eslint-config-next: N/A
react: 19.2.0
react-dom: 19.2.0
typescript: 5.9.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
cacheComponents, internationalization (i18n)
Which stage(s) are affected? (Select all that apply)
next build (local), next dev (local), Vercel (Deployed)
Additional context
Every big localization framework which works with react server components (I have tried intlayer, next-intl and lingui), breaks when using it with cache components. The reason that they break seems to be that we are accessing params, which forces the route to be dynamic. Even if I cache the locale param at the layout level, when I access my params at page level I opt out since that is an asynchronous call. The result is that if you translate any content at all (in server components), your entire page becomes dynamic. All of the big localization framework demands that you do this to translate server side components.
Found that if you put generateStaticParams at each dynamic segment it seems to work as I want it to. It feels like this is unintended however. If it is intended it would be a very nice thing to document.
A more clear doc update is in review/draft, but I think even that might also miss on the benefits of prerendering when theres' two params too, cuz /every-locale/[id] will also generate a static shell, per locale value.
Anyway, the docs do have some thin info about this, param is runtime data unless generateStaticParams is defined to return at least one param.
I'll get better soon 🙏
Hey @icyJoseph, in my case the [locale]/[...not-found] route causes the same error
Removing /src/app/[locale]/(landing)/[...not-found]/page.tsx fixes it
Hey @icyJoseph, in my case the
[locale]/[...not-found]route causes the same errorRemoving
/src/app/[locale]/(landing)/[...not-found]/page.tsxfixes it
What route are you left with when you've removed /src/app/[locale]/(landing)/[...not-found]/page.tsx? Or are you referring to the route group (landing)?
@aymericzip
tree .
.
├── intlayer.config.ts
├── next.config.ts
├── node_modules
├── src
│ ├── app
│ │ ├── [locale]
│ │ │ ├── (landing)
│ │ │ │ ├── [...not-found]
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── metadata.content.ts
│ │ │ │ │ ├── metadata.ts
│ │ │ │ │ ├── not-fount.content.ts
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── 404
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── page.tsx
...
├── tsconfig.json
└── types
└── markdown.d.ts
The error was showing on every page, and after I removed the [...not-found]/** content, it disappeared
Gemini found the issue :
The error "Uncached data was accessed outside of <Suspense>" occurs because you are using the Next.js 16 Cache Components feature (likely the experimental.ppr or dynamic IO flags), which enforces strict rules about data fetching and dynamic access.
Here is the explanation:
Why [...not-found]?
Your other pages are likely Static because you have generateStaticParams in apps/website/src/app/[locale]/layout.tsx. This means they are pre-rendered at build time, so they don't trigger runtime data access checks.
The [...not-found] route is a catch-all route. Since it cannot statically generate every possible unknown URL, it runs Dynamically (at runtime) for every request that doesn't match a static path.
The "Uncached Data" Issue:
When [...not-found] renders at runtime, it uses PageLayout, which renders <IntlayerClientProvider>.
It appears IntlayerClientProvider (or a component it renders) is performing a data fetch (e.g., loading dictionaries) or accessing dynamic data (headers/cookies) that is not cached.
@adamsoderstrom