Description
Describe the bug
Hi, when I have ISR set up for a dynamic route (eg [dynamicId]/page.tsx
) the revalidate
time is ignored and the page is rebuilt on every page load.
The same nextjs project deployed to Vercel without OpenNext will correctly wait out the timer before regenerating.
I also have a static route deployed to the same Cloudflare worker and that does wait out the revalidate time, so I don't think it's an issue with my R2/doQueue setup.
The dynamic route is listed as "SSG" during build time:
Route (app) Size First Load JS Revalidate Expire
┌ ○ / 139 B 101 kB 5m 1y
├ ○ /_not-found 977 B 102 kB
└ ● /[dynamicId] 139 B 101 kB
+ First Load JS shared by all 101 kB
├ chunks/4bd1b696-67ee12fb04071d3b.js 53.2 kB
├ chunks/684-42609a042cd3abcf.js 45.9 kB
└ other shared chunks (total) 1.89 kB
○ (Static) prerendered as static content
● (SSG) prerendered as static HTML (uses generateStaticParams)
Demo:
Using export const revalidate = 300
. I've linked the repo below.
Deployed to Cloudflare Worker (triggers regeneration every pageload):
Screencast.From.2025-06-30.11-34-33.webm
Deployed to Vercel (will not regenerate until the revalidate time):
Screencast.From.2025-06-30.11-31-51.webm
Steps to reproduce
Minimal repro - [dynamicId]/page.tsx
:
https://github.com/gianjohansen/isr-revalidate-frequency
You can see it deployed here:
OpenNext: https://isr-revalidate-frequency.gian-johansen.workers.dev/123
Vercel: https://isr-revalidate-frequency-vercel.vercel.app/123
A static page on the same Cloudflare worker which does have working ISR:
https://isr-revalidate-frequency.gian-johansen.workers.dev
The dynamic route uses this code:
type Params = Promise<{ dynamicId: string }>;
export const revalidate = 300;
export const dynamicParams = true;
export async function generateStaticParams() {
return []; // no generated pages at build time
}
export default async function DynamicPage({ params }: { params: Params }) {
const { dynamicId } = await params;
const buildTime = new Date().toLocaleTimeString();
const nextBuildTime = new Date(Date.now() + revalidate * 1000).toLocaleTimeString();
return (
<div className="flex flex-col gap-1 items-center justify-center h-screen">
<p>Dynamic ID: {dynamicId}</p>
<p>Last built at: <strong>{buildTime} (UTC)</strong></p>
<p>Should regenerate at: <strong>{nextBuildTime} (UTC)</strong></p>
</div>
);
}
Expected behavior
The page should only regenerate after the revalidate time has passed. Should match the behaviour of the Vercel deployment.
@opennextjs/cloudflare version
1.3.1
Wrangler version
4.22.0
next info output
Operating System:
Platform: linux
Arch: x64
Version: #28-Ubuntu SMP PREEMPT_DYNAMIC Mon May 19 14:45:34 UTC 2025
Available memory (MB): 31728
Available CPU cores: 32
Binaries:
Node: 22.14.0
npm: 10.9.2
Yarn: N/A
pnpm: 10.11.0
Relevant Packages:
next: 15.3.4 // Latest available version is detected (15.3.4).
eslint-config-next: 15.3.4
react: 19.1.0
react-dom: 19.1.0
typescript: 5.8.3
Next.js Config:
output: N/A
Additional context
No response