#CacheComponents

1 messages · Page 1 of 1 (latest)

tribal mapleBOT
#

Hi @royal halo. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

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:

  1. Mark the route as dynamic so it doesn’t attempt prerendering.
  2. 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: true globally.
  • 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: true when a GET Route Handler uses req.url during prerender.
  • For OAuth callbacks and similar APIs, mark the route as dynamic so prerender is skipped.
  • Use cacheLife / use cache only 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.

royal halo
#

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

tribal mapleBOT
#

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 when cacheComponents is 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: NextRequest vs req alone does not change anything.
  • export const dynamic = 'force-dynamic' is explicitly called out as “not needed” / disabled under cacheComponents. [Migrating configs]

For your case (OAuth callback and /api/games):

  • Accessing req.url is 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 cacheComponents is enabled, beyond the general behavior that prerendering stops when runtime data is accessed.

Given the docs:

#
  • You should keep using req.url where 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 dynamic option) 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.

royal halo
#

@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

tribal mapleBOT
#

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 the NEXT_PRERENDER_INTERRUPTED error 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 req vs req: NextRequest is just typing; it doesn’t change behavior.
  • With cacheComponents: true, route segment configs like dynamic = '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 when headers() 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 like dynamic are 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:

  1. 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
    }
    
  2. Use cacheComponents and use cache only where you don’t need request-specific data, e.g. data that can be shared across users and doesn’t depend on req.url, cookies, headers, etc. [CacheComponents; Route handlers caching]

  3. If the NEXT_PRERENDER_INTERRUPTED error 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.

royal halo
tribal mapleBOT
#

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 like req.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:

#
  1. Your OAuth callback and /api/games handlers are allowed to use req.url; that just means they can’t be fully prerendered and must run at request time. [Route handlers caching]
  2. The NEXT_PRERENDER_INTERRUPTED message is how Next.js reports that prerendering bailed out when it hit req.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.
  3. There is no documented per-route flag (other than the now-“not needed” dynamic config) to force a GET Route Handler to be fully dynamic when cacheComponents is 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.url in handlers that must depend on the request (OAuth, query parsing).
  • Use cacheComponents / use cache only around data that doesn’t depend on runtime APIs (no req.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.

royal halo
#

How about using experimenta.hideLogsAfterAbort @tribal maple

tribal mapleBOT
#

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:

  • cacheComponents itself 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 when cacheComponents is enabled. [Migrating configs]
  • How Route Handlers behave with Cache Components, including the NEXT_PRERENDER_INTERRUPTED behavior when runtime data like req.url is 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.

royal halo
#

@tribal maple How about this error:

export default function Footer() {
    const year = new Date().getFullYear();

    return (
        <footer className="p-4 text-center">
            <div>
                <p>&copy; {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-prerender to 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
tribal mapleBOT
#

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:

  1. Be explicitly deferred to request time (by calling a dynamic API like await connection() first), or
  2. 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>&copy; {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 calling new 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.

The knowledge sources do not give a simple “add this line to Footer” solution; they only describe the general rules for Date/Math.random() under Cache Components and dynamicIO.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: