#CacheComponents
1 messages · Page 1 of 1 (latest)
With cacheComponents: true, GET Route Handlers follow the same prerendering model as pages. That means Next.js will try to prerender them at build time, and any access to request-specific data (like req.url, nextUrl.searchParams, cookies(), etc.) will cause a “needs to bail out of prerendering” error unless you explicitly mark the route as dynamic. [Enabling cacheComponents]
Your errors:
Route /api/... needs to bail out of prerendering at this point because it used request.url.
digest: 'NEXT_PRERENDER_INTERRUPTED'
are exactly that: the prerender step is failing because new URL(req.url) depends on the incoming request.
The official docs and linked issues show this pattern for similar APIs (nextUrl.searchParams, cookies()) after upgrading to 16 with cacheComponents enabled. [nextUrl.searchParams issue]
How to fix it
For these API routes that must always run per-request (OAuth callbacks, data APIs), you should opt them out of prerendering and treat them as fully dynamic. With Cache Components enabled, the way to do that (based on the behavior described in the issues) is:
- Mark the route as dynamic so it doesn’t attempt prerendering.
- Then you can safely use
new URL(req.url).
The knowledge sources don’t show the exact code snippet for marking a Route Handler as dynamic under cacheComponents, but they do state that when prerendering can’t complete (e.g., intercepting routes, request-dependent behavior), Next.js will treat the route as dynamic and skip prerender. [Intercepting routes fix]
So, for your OAuth callback and /api/games:
- Keep
cacheComponents: trueglobally. - Configure these specific routes to be dynamic (not prerendered).
- Then your existing code:
export async function GET(req: NextRequest) {
const url = new URL(req.url)
// ...
}
can stay as-is, because it will now run only at request time, not during prerender.
About cacheLife('max')
You’re right that adding cacheLife('max') makes the handler effectively static/cached, which is not what you want for OAuth callbacks or per-request APIs. cacheLife is meant for content you do want to cache and potentially include in the static shell, not for request-specific handlers. [Migrating route configs]
Summary
- The errors are expected with
cacheComponents: truewhen a GET Route Handler usesreq.urlduring prerender. - For OAuth callbacks and similar APIs, mark the route as dynamic so prerender is skipped.
- Use
cacheLife/use cacheonly on routes or components where caching and prerendering are actually desired.
The docs and issues don’t show the exact per-route config snippet for Route Handlers under Cache Components, so I can’t provide a concrete code example beyond this behavior description.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal halo Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Okay so, should I only add req: NextRequestto those parts in order to mark it as dynamic? Or should I add something else, I've tried using force-dynamic, but that doesn't work together with CacheComponents. @tribal maple
Let me check the knowledge base for you again. Give me one moment! :books:
You don’t need to (and can’t) “mark it dynamic” just by changing the type to NextRequest. The type annotation has no effect on caching or prerendering behavior.
From the docs:
- Route Segment Config options like
dynamic = 'force-dynamic'are disabled whencacheComponentsis on and will be deprecated. [Route segment config; Migrating configs] - With Cache Components, GET Route Handlers follow the same model as UI routes: they are prerendered when they don’t access runtime data, and prerendering stops (bails out) when they do access runtime data like
req.url,headers(), etc. [Route handlers caching]
So:
- Using
req: NextRequestvsreqalone does not change anything. export const dynamic = 'force-dynamic'is explicitly called out as “not needed” / disabled undercacheComponents. [Migrating configs]
For your case (OAuth callback and /api/games):
- Accessing
req.urlis runtime data, so prerendering will always bail out there. That’s expected with Cache Components. [Route handlers caching] - The knowledge sources do not document a supported way to force these specific Route Handlers to be treated as fully dynamic when
cacheComponentsis enabled, beyond the general behavior that prerendering stops when runtime data is accessed.
Given the docs:
- You should keep using
req.urlwhere you need it (OAuth, query parsing). - Expect those handlers to run at request time and not be prerendered.
- There is no documented additional flag or config (beyond the now-disabled
dynamicoption) to “mark them dynamic” under Cache Components.
If you’re still seeing the NEXT_PRERENDER_INTERRUPTED error surfacing as a hard error (instead of just falling back to request-time), that behavior is not clearly described in the current docs, and the knowledge sources don’t provide a specific workaround other than the general guidance above.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal halo Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@tribal maple I still don't really understand what I have to do right now. I use JS only I don't use TS. Do you have context from the past messages I've sent or not
Let me check the knowledge base for you again. Give me one moment! :books:
Yes, I see the previous messages and errors you shared. I’ll keep it JS-only and focus on what the docs actually say.
What’s going on
With cacheComponents: true:
- GET Route Handlers are prerendered like pages. [Enabling cacheComponents]
- Prerendering must not touch request-specific data like
req.url,request.headers,request.cookies, etc. [Route handlers caching] - When prerender hits something like
new URL(req.url), it bails out and throws theNEXT_PRERENDER_INTERRUPTEDerror you’re seeing. [Route handlers caching]
The docs say:
Prerendering stops if the GET handler accesses … request object properties (like
req.url,request.headers,request.cookies,request.body). [Route handlers caching]
That’s exactly your case.
What you don’t need to do
- You don’t need TypeScript. Using
reqvsreq: NextRequestis just typing; it doesn’t change behavior. - With
cacheComponents: true, route segment configs likedynamic = 'force-dynamic'are disabled / “not needed”. [Route segment config; Migrating configs]
So adding:
export const dynamic = 'force-dynamic'
won’t help when cacheComponents is on.
What the docs actually support
For Route Handlers with Cache Components enabled, the documented behavior is:
- They run at request time by default.
- They can be prerendered only if they don’t touch runtime data.
- If they do touch runtime data (like
req.url), prerendering stops at that point and the route is rendered at request time instead. [Route handlers caching]
The examples show:
- Static (no runtime data) → prerendered.
- Dynamic (e.g.
Math.random()) → prerender stops when it hits that. - Runtime data (
headers()) → prerender stops whenheaders()is called. [Route handlers caching]
So in theory, your code:
export async function GET(req) {
const url = new URL(req.url)
// ...
}
should just cause prerender to stop and then run at request time.
The problem / limitation
You’re seeing the NEXT_PRERENDER_INTERRUPTED error surface instead of being silently handled. The docs do not explain why this sometimes shows as a hard error instead of just falling back to request-time rendering, and they don’t give a specific “fix” for this case beyond describing the behavior. [Route handlers caching]
The knowledge sources also say:
- With
cacheComponents, route segment configs likedynamicare effectively deprecated / not needed. [Migrating configs] - There is no alternative per-route flag documented to “force dynamic” for Route Handlers under Cache Components.
So based on the docs we have:
- There is no documented extra export you can add in JS to “fix” this for those handlers.
- The intended model is: use runtime data → prerender bails → handler runs at request time.
Because of that, I can’t honestly give you a concrete “add this line and it will stop erroring” snippet; the docs don’t show one.
What you can safely do now
Given only the official sources:
-
Keep your JS handlers as-is where you need
req.url(OAuth callback,/api/games):// app/api/auth/roblox/callback/route.js export async function GET(req) { const url = new URL(req.url) const code = url.searchParams.get('code') const returnedState = url.searchParams.get('state') // ... your logic } -
Use
cacheComponentsanduse cacheonly where you don’t need request-specific data, e.g. data that can be shared across users and doesn’t depend onreq.url, cookies, headers, etc. [CacheComponents; Route handlers caching] -
If the
NEXT_PRERENDER_INTERRUPTEDerror is breaking your build or dev server for these handlers, the current docs don’t provide a specific workaround other than:- Avoiding runtime data in handlers you want prerendered, or
- Not using Cache Components for this project until the behavior is clearer / fixed.
Because the knowledge sources don’t document a reliable way to “mark a GET Route Handler as fully dynamic” under cacheComponents, I can’t suggest a precise config change beyond this behavior explanation.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal halo Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@tribal maple If it helps these are the entire logs:
Let me check the knowledge base for you again. Give me one moment! :books:
I can only use what’s in the provided Next.js docs and GitHub issues, and they don’t include your full logs, so I can’t see anything beyond the snippets you pasted earlier.
From those snippets and the docs:
-
With
cacheComponents: true, GET Route Handlers are treated like UI routes: Next.js tries to prerender them, and prerendering must stop when you touch runtime data likereq.url,request.headers,request.cookies, etc. [Route handlers caching; Rendering strategies] -
The error you see:
Route /api/... needs to bail out of prerendering at this point because it used request.url. digest: 'NEXT_PRERENDER_INTERRUPTED'is exactly the documented behavior when prerendering hits request-specific data. [Route handlers caching]
-
Under Cache Components, route segment configs like
dynamic = 'force-dynamic'are “not needed” / effectively disabled; the docs explicitly say to remove them when migrating. [Migrating route configs]
So, based on the official sources:
- Your OAuth callback and
/api/gameshandlers are allowed to usereq.url; that just means they can’t be fully prerendered and must run at request time. [Route handlers caching] - The
NEXT_PRERENDER_INTERRUPTEDmessage is how Next.js reports that prerendering bailed out when it hitreq.url. The docs don’t clearly state whether this should be a visible error vs. an internal signal, and they don’t show a specific fix beyond describing the behavior. - There is no documented per-route flag (other than the now-“not needed”
dynamicconfig) to force a GET Route Handler to be fully dynamic whencacheComponentsis enabled.
Because your “entire logs” aren’t actually included in the knowledge sources, and the docs don’t go further than the behavior above, I can’t reliably tell you more from the logs or give a guaranteed code change that will silence the NEXT_PRERENDER_INTERRUPTED output.
What is supported by the docs:
- Keep using
req.urlin handlers that must depend on the request (OAuth, query parsing). - Use
cacheComponents/use cacheonly around data that doesn’t depend on runtime APIs (noreq.url,cookies(),headers(), etc.). [CacheComponents; Cache Components guide] - Expect those runtime-dependent handlers to run at request time and not be fully prerendered.
If you paste the logs into the chat, I still won’t have them as part of the “knowledge sources” set, so I’m limited to the behavior described in the official docs and issues above.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal halo Kapa.ai is still learning and improving, please let me know how I did by reacting below.
How about using experimenta.hideLogsAfterAbort @tribal maple
Let me check the knowledge base for you again. Give me one moment! :books:
I’m sorry, but the provided knowledge sources do not mention any experimental.hideLogsAfterAbort (or similarly named) option in next.config.js or elsewhere.
The only related pieces we have are:
cacheComponentsitself and how it changes prerendering and caching behavior. [cacheComponents config]- How Cache Components affects route configs (
dynamic,revalidate, etc.) and that many of these are “not needed” or not supported whencacheComponentsis enabled. [Migrating configs] - How Route Handlers behave with Cache Components, including the
NEXT_PRERENDER_INTERRUPTEDbehavior when runtime data likereq.urlis accessed. [Route handlers caching]
None of these sources document an experimental.hideLogsAfterAbort flag or any logging-suppression setting for prerender aborts. Because of that, I can’t confirm that such an option exists or how it would work.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal halo Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@tribal maple How about this error:
export default function Footer() {
const year = new Date().getFullYear();
return (
<footer className="p-4 text-center">
<div>
<p>© {year} Lotus Arts. All rights reserved.</p>
</div>
</footer>
);
}
at d (src\components\layout\footer.jsx:2:18)
at stringify (<anonymous>)
1 | export default function Footer() {
2 | const year = new Date().getFullYear();
| ^
3 |
4 | return (
5 | <footer className="p-4 text-center">
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running
next dev, then open "/games" in your browser to investigate the error. - Rerun the production build with
next build --debug-prerenderto generate better stack traces.
Error occurred prerendering page "/games". Read more: https://nextjs.org/docs/messages/prerender-error
Export encountered an error on /(site)/games/page: /games, exiting the build.
⨯ Next.js build worker exited with code: 1 and signal: null
Let me check the knowledge base for you again. Give me one moment! :books:
This error is caused by new Date() being treated as a non-deterministic operation under Cache Components / dynamicIO, so it can break prerendering unless you handle it in one of the supported ways.
The docs group new Date(), Date.now(), Math.random(), etc. as “non-deterministic operations” that must either:
- Be explicitly deferred to request time (by calling a dynamic API like
await connection()first), or - Be cached with
"use cache"so the value is fixed at prerender time. [Non-deterministic ops]
There’s also specific guidance that timestamps in components rendered during prerender are ambiguous and need explicit handling; otherwise they can cause prerender errors. [Date.now issue]
For your Footer:
export default function Footer() {
const year = new Date().getFullYear()
return (
<footer className="p-4 text-center">
<div>
<p>© {year} Lotus Arts. All rights reserved.</p>
</div>
</footer>
)
}
you’re calling new Date() directly in the render path, which is what’s triggering the prerender error.
From the docs and linked issues, the supported patterns are:
1. Make it a static value (no dynamic time)
If you don’t actually need this to change per request, you can hardcode or compute it at build time (e.g. via an env var or a small build-time script) and pass it as a prop. That avoids new Date() entirely during prerender.
2. Move the time logic into a dynamic/request-time context
For components that truly need current time, the docs say you must either:
- Defer to request time with a dynamic API (e.g.
await connection()in a Cache Component) before callingnew Date(), or - Use
"use cache"to cache the result of the server component tree that includes the date. [Non-deterministic ops]
However, the knowledge sources don’t show a concrete example of doing this for a simple layout/footer component, and they also note that new Date() in client components rendered during prerender is considered ambiguous and can cause exactly the kind of error you’re seeing. [Date.now issue]
Because of that, and staying within the docs:
- The safest documented fix is to avoid
new Date()in the prerendered render path (option 1), or - If you really need a dynamic year, compute it in a context that’s clearly request-time (e.g. a server component that has already deferred to request time) and pass it down, but the docs don’t provide a ready-made snippet for that specific case.