Back to Next Js

per-page decisions: removing `instant = false`

skills/next-cache-components-adoption/references/per-page-decisions.md

16.3.03.8 KB
Original Source

per-page decisions: removing instant = false

Read this when a route still blocks after you remove its instant = false and the dev overlay's fix card isn't enough on its own. Each section here covers a judgment call the agent shouldn't make alone.

deciding what to do with a blocking read

Read the full linked page behind the fix card — not only the inline snippet — before editing. The card unblocks the build, but the page covers the details that make the route's navigation actually instant (e.g. where to place a <Suspense> boundary). Don't improvise.

If you're unsure which fix fits, the right call usually depends on what this part of the page is for, which the code doesn't capture. Ask the user about their goal for it rather than guessing. Frame it as a product/UX question: should this content be there instantly on load, or is it fine for it to stream in a moment later? Should everyone see the same thing (cacheable) or is it per-user / per-request? Tie the technical fix to that answer (cache it, wrap it in <Suspense>, or keep it request-time), so they're deciding the experience, not the API.

security gates and other code you can't infer

If the blocking code looks like it's there for a reason you can't infer — a security gate at the page top (await verifyAccess(), an auth redirect, a feature-flag check) where moving it inside <Suspense> would change what the code guarantees — stop and ask the user before refactoring. The build error wants <Suspense>, but wrapping a gate in <Suspense> defeats the gate. Only the person who wrote it knows whether to keep the route blocking (instant = false as a documented Block), restructure the page so the gate runs differently, move the check to Proxy, or — if the gate duplicates protection the app already relies on elsewhere (platform auth such as Vercel Deployment Protection, a Proxy check, a Data Access Layer) — remove it.

Relocating a read (await connection(), Proxy) only changes where it runs, never whether it should run at all — so a gate that's redundant or broken looks identical to a correctly-placed one through the fix card's lens. If a gate looks strange, redundant, or out of place, say so plainly — "this looks like it might be unnecessary here — are you sure it belongs?" — instead of quietly relocating it. Surfacing the doubt is the agent's job; deciding is the user's.

If every route under a layout is gated this way, a documented Block on the layout is the correct end state. Moving the gate to Proxy is the architectural fix, not a Cache Components one, and that's a follow-up rather than something to hold the migration on.

For the broader picture, read the Authentication guide (where auth checks belong: Proxy for routing, Data Access Layer for data) and the Data Access Layer section of Data Security (centralized auth checks that compose with 'use cache').

If you don't know how to make a piece of code Cache Components–correct without changing what it does, ask.

when to leave a Block in place

If a route is genuinely meant to block — it's inherently per-request with no useful static shell — or the refactor would be large and the user would rather not take it on now, that's a legitimate outcome. Keep instant = false, but confirm it with the user first and turn its // TODO: Cache Components adoption comment into a reason, e.g. // instant = false: kept on purpose — fully request-time dashboard or // instant = false: deferred, refactor too large for now.

A documented, deliberate Block is fine to leave after the migration; an undocumented leftover opt-out is not.