Cannot build with dynamicIO enabled.
Opened this issue · 7 comments
Describe the Bug
When enabling the experimental dynamicIO feature, the following error occurs during build:
Error occurred prerendering page "/admin/[[...segments]]". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Route "/admin/[[...segments]]" has a `generateMetadata` that depends on Request data (`cookies()`, etc...) or external data (`fetch(...)`, etc...) but the rest of the route was static or only used cached data (`"use cache"`). If you expected this route to be prerenderable update your `generateMetadata` to not use Request data and only use cached external data. Otherwise, add `await connection()` somewhere within this route to indicate explicitly it should not be prerendered.
Export encountered an error on /(payload)/admin/[[...segments]]/page: /admin/[[...segments]], exiting the build.
While this is experimental, the documentation for the new 'use cache'
directive states that it aims to replace the unstable_cache
API.
Given that we will be using the payload client directly in Server Actions, we will need a way to cache those actions with tags (for revalidateTag
). React's cache
doesn't support tagging for manual revalidation, which leaves only Next's unstable_cache
and 'use cache'
with cacheTag
as options.
Link to the code that reproduces this issue
blank
Reproduction Steps
Enable experimental dynamicIO feature.
Build.
Which area(s) are affected? (Select all that apply)
area: core
Environment Info
Payload: beta-119
Node: 20
Next.js: 15.0.2-canary.9
Oh man thanks for the report here. This is a real can of worms. You're right, Next.js throws an error here but I am not sure why.
Reading the error, it basically says that generateMetadata
depends on request data, but the rest of the page does not.
However, this is 100% untrue as our Page
component definitely uses headers()
which would opt the whole route into not being able to be prerendered.
I think this might be a Next.js canary thing...
I also just updated our /admin/[[...segments]]
page template as the error message instructed, by adding await connection()
but this did not fix the build error.
// import { connection } from 'next/server'
const Page = async ({ params, searchParams }: Args) => {
await connection()
return RootPage({ config, params, searchParams, importMap })
}
Gonna have to look into this one a bit further and get back to you!
got the same error and the
await connection() doesn't help
import React, { FC } from 'react'
import { Metadata } from 'next'
import { connection } from 'next/server'
type DashboardProps = {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export const generateMetadata = async (
props: DashboardProps
): Promise<Metadata> => {
const searchParams = await props.searchParams
const { page: currentPage } = searchParams
return {
description: `${currentPage}`,
}
}
const Page: FC<DashboardProps> = async () => {
await connection()
return <div>Page</div>
}
export default Page
and the log:
Next.js 15.0.2-canary.11
- Environments: .env.local, .env
- Experiments (use with caution):
· turbo
· dynamicIO
Creating an optimized production build ...
✓ Compiled successfully
✓ Linting and checking validity of types
✓ Collecting page data
Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Route "/" has a `generateMetadata` that depends on Request data (`cookies()`, etc...) or external data (`fetch(...)`, etc...) but the rest of the route was static or only used cached data (`"use cache"`). If you expected this route to be prerenderable update your `generateMetadata` to not use Request data and only use cached external data. Otherwise, add `await connection()` somewhere within this route to indicate explicitly it should not be prerendered.
Export encountered an error on /(public)/page: /, exiting the build.
⨯ Static worker exited with code: 1 and signal: null
node -v
v22.11.0
Instead of using await connection()
at the page level, wrapping the layout with <Suspense>
solved the problem for me.
app/(payload)/layout.tsx
import configPromise from "@payload-config";
import "@payloadcms/next/css";
import { RootLayout } from "@payloadcms/next/layouts";
import React, { Suspense } from "react";
import "./custom.scss";
import { importMap } from "./admin/importMap";
type Args = {
children: React.ReactNode;
};
const Layout = ({ children }: Args) => (
<Suspense>
<RootLayout importMap={importMap} config={configPromise}>
{children}
</RootLayout>
</Suspense>
);
export default Layout;
See also the Next.js blog entry: Our Journey with Caching - Dynamic
I can't judge whether that's technically correct. My understanding of Next.js isn't deep enough for that.
I think wrapping the layout this high up would have a negative impact on the /api
routes as well, but I'm not certain about that. I did also try wrapping the app/(payload)/admin/[[segments]]/page.tsx
RootPage with Suspense, as well as creating a loading.tsx
file (also generates a Suspense boundary), and finally creating a app/(payload)/admin/layout.tsx
wrapping the children
prop with Suspense. None of those worked.
It is interesting though that wrapping the root payload layout with Suspense works. This seems to indicate there's something in RootLayout
causing the issue rather than RootPage
as the error suggests.
This error said:
throw new CanaryOnlyError('experimental.dynamicIO');
^
CanaryOnlyError: The experimental feature "experimental.dynamicIO" can only be enabled when using the latest canary version of Next.js.
just upgrade npm i next@canary
@pedroaparecido As listed originally in my issue post, canary is being used. When you install canary, and enable dynamicIO, this issue occurs. While this is a canary-only option now, it has been stated by the Next.JS team to be the expected successor to the unstable_cache
function. This would make the new use cache
directive the only first-party way to cache server actions that use the local payload API with the ability to tag each cache and manually invalidate them.
Just bumped into this issue as well trying to deploy to Vercel.
@Figumari solution worked but I am getting the exact same error on my dynamic routes now too, outside of admin/
.