DEV Community

Cover image for NextJS 15 Gimmicks
Akshat Ramanathan
Akshat Ramanathan

Posted on

NextJS 15 Gimmicks

NextJS: A clash with Cache

A curated list of all NextJS 15 gimmicks

Default Next (App router) behaviours -

  1. Static build all pages unless dynamic apis used like cookies or header or force-dynamic in any subcomponents.
  2. If child component as part of page is dynamic, whole page becomes dynamic. To stream and improve load times, use Suspense boundaries in dynamic parts
  3. API calls in components are cached by default unless no-store header is given as custom config (architecture/framework/infra level hack)
  4. Opt in to "use cache", cacheLife and cacheTag with DynamicIo experimental flag (cacheCompoments in v16) makes API or async calls dynamic and not built statically. Often used with PPR and if caching response required use fetch "store" header or “use cache”
  5. Loading tsx wrappers inside layout. Do not do dynamic stuff in layout as next requires clean static path of components for clear separate boundaries. If layout becomes dynamic whole subtree is forced SSR’d
  6. Streaming only works with app router as RSCs can be streamed down, often used with suspense boundaries.
  7. In suspense previously we had to manually throw promises but in react 19 (next 15+) use() hook removes boilerplate and makes it easy.
  8. Previously, suspense children promises were initialized in parallel and resolve boundary when slowest component/promise resolves so all is batched and shown at once. In React 19 (Next 15) Suspense children no longer concurrent/parallel. They cause waterfall. To avoid, use separate boundaries with loading fallbacks or hoist promise to parent and pass as prop and internal use() hook in children for parallel/concurrent behaviour. Another option, promise.all them in parent after hoisting.
  9. Middleware’s are badly named interceptors and not good for auth and publicly exposed (renamed proxy in v16). Do not use auth logic here. Use for checks and redirects.
  10. Server actions are public endpoints created on build time. Use with daytime and auth to ensure safety.
  11. Client components are SSRd first, then hydrated on client (ensure isomorphic code, fallbacks for DOM APIs, etc.) but server components are only in server as static (RSC payload streamed at runtime)
  12. Streaming RSC payload is converted to vdom nodes on client and hydrated. Hence bundler specific splitting required to split server and client references from isomorphic code with directives like "use client".
  13. Wrapping API calls of server components in suspense also makes it dynamic and not cache the API result. (By default caches unless no-store header). Otherwise caches coz renders static by default. Opt into cache static with “use cache” explicitly mentioned in function or component level. (DynamicIO flag or cacheComponents in v16). If data fetching in layouts, can cache it for example, to improve loading speeds. CacheTag or revalidareTag with expireTag and cacheLife to opt into ISR caching revalidation behaviour explicitly.
  14. If dynamicIO flag is used with async calls, do "use cache" explicitly or wrap with suspense to force dynamic behaviour. We can also use loading tsx. Same functionality as suspense.
  15. Non suspending async components always blocks (dynamic content finishes loading) rendering, then streamed together causing delay

Summary -
Opt into into static max with suspense = PPR
PPR - opt in static part caching with suspense boundary. No forced SSR if small chunk dynamic in page.
Opt into async stuff excluded unless cached during build of ppr/static.
DynamicIO - cache by default (as static SSG behaviour) (cached API response) to opt in cache with “use cache”. No more "force-dynamic" required

Old Next - Pages router

  1. GetServerSideProps work like remix loaders
  2. GetStaticSideProps (like Gatsby) works only during build
  3. Generate static routes on build with generate static paths or some function like that.
  4. No server actions, we used tRPC as a bridge way of calling type safe APIs present in server from client. Under the hood sets up a RPC client and calls functions in server securely

Top comments (0)