How would you optimize this Next.js 16 Cache Components setup for highly dynamic pages?
Unanswered
Ariegeois posted this in #help-forum
AriegeoisOP
We're looking for advice on whether our Next.js 16 architecture is aligned with Cache Components best practices and where the biggest performance wins might be.
Current setup
Next.js 16.2.12
App Router
cacheComponents: true
reactCompiler: true
No "use cache" for transactional reads (intentional to avoid stale-after-write issues)
Primary data is fetched via uncached Drizzle queries
TanStack Query is only used for secondary, non-blocking data after first paint
Our detail pages follow:
Page
└── <Suspense fallback={<Loading />}>
└── async DetailComponent
The skeleton appears instantly, but the content streams in after ~100–400ms.
The critical path is roughly:
getSession()
getFreshAccountStatus() (2 uncached DB queries)
getPropertyById() (uncached query + access resolution + signed URLs)
One page (projects/[id]) also currently calls await connection(), making the segment fully dynamic.
From our understanding, staleTimes only affects the client router cache and not this initial render.
Question: Given that we prioritize fresh authorization and transactional consistency over caching, what would you recommend to improve perceived performance? Should we focus on reducing DB round trips, restructuring Suspense boundaries, request-level deduplication, selectively caching certain reads, or something else?
Current setup
Next.js 16.2.12
App Router
cacheComponents: true
reactCompiler: true
No "use cache" for transactional reads (intentional to avoid stale-after-write issues)
Primary data is fetched via uncached Drizzle queries
TanStack Query is only used for secondary, non-blocking data after first paint
Our detail pages follow:
Page
└── <Suspense fallback={<Loading />}>
└── async DetailComponent
The skeleton appears instantly, but the content streams in after ~100–400ms.
The critical path is roughly:
getSession()
getFreshAccountStatus() (2 uncached DB queries)
getPropertyById() (uncached query + access resolution + signed URLs)
One page (projects/[id]) also currently calls await connection(), making the segment fully dynamic.
From our understanding, staleTimes only affects the client router cache and not this initial render.
Question: Given that we prioritize fresh authorization and transactional consistency over caching, what would you recommend to improve perceived performance? Should we focus on reducing DB round trips, restructuring Suspense boundaries, request-level deduplication, selectively caching certain reads, or something else?
5 Replies
AriegeoisOP
is cached components actually the best play here? we have a dashboard setup currently with a lot of different routes etc.
It feels like you don't really need cache components, caching is not bad, but we all know the classic argument that the hardest thing in programming is Cache invalidation. A technique I use to give me granular control over in validation while using cache components involves using more than one cache tag
Then say we add a project and it is on page 2 we can invalidate all pages at once with
As long as your invalidating cache tags which I admit can be quite cumbersome caching is your friend
cacheTag(`projects-${orgId}-${page}` ,`projects-${orgId}`) Then say we add a project and it is on page 2 we can invalidate all pages at once with
updateTag(`projects-${orgId}`)As long as your invalidating cache tags which I admit can be quite cumbersome caching is your friend
The idea with cache components is to get as much to the screen as possible as fast as possible and resolve the data as close to it being used as possible
I'm in the camp that thinks even with dynamic data a page should never be async, if you need dynamic data use .then() and pass it down and resolve it lower on the tree
No await on the page !