In Next.js, you prefetch data for CSR pages primarily through the built-in <Link> component's automatic prefetching, which loads route resources in the background, combined with client-side data libraries like SWR that leverage caching to eliminate redundant requests
Prefetching in Next.js is a built-in optimization that loads resources for routes before the user navigates to them, making transitions feel instant. For CSR-heavy pages, this is particularly valuable because it combines the SEO benefits of server-rendered shells with the interactive richness of client-side data fetching. Next.js provides multiple prefetching mechanisms: automatic prefetching via the <Link> component, manual prefetching with the useRouter hook, and data-level prefetching through libraries like SWR or TanStack Query that leverage caching and revalidation. The goal is to ensure that when a user clicks a link, the necessary JavaScript, React Server Components payload, and data are already available in the browser cache .
Automatic Link prefetching: The <Link> component automatically prefetches routes when they enter the viewport or when the user hovers over them, downloading the associated JavaScript and RSC payloads in the background [citation:6][citation:9].
Viewport-based scheduling: Next.js prioritizes prefetching based on visibility—links in the viewport are prefetched first, followed by those showing user intent (hover/touch), with newer links replacing older ones in the queue [citation:6].
Manual prefetching: The useRouter().prefetch() method allows programmatic prefetching for routes not yet in the viewport or in response to analytics, scroll events, or other custom triggers [citation:6].
Data library caching: SWR and TanStack Query provide client-side caching that eliminates redundant data fetching after navigation, making page transitions feel instantaneous once the initial load completes [citation:3][citation:8].
Next.js adapts its prefetching strategy based on route type. For static routes (those that can be fully generated ahead of time), the entire page is prefetched and cached in the browser for 5 minutes by default. For dynamic routes, prefetching is more conservative—if you have a loading.tsx file, Next.js prefetches the layout up to the loading boundary and caches it for 30 seconds, showing the loading UI immediately upon navigation while the rest of the page streams in. Without loading.tsx, dynamic routes skip prefetching entirely to avoid unnecessary server work for routes users may never visit . This design balances performance with resource consumption [citation:6][citation:9].
For routes not automatically prefetched (e.g., links outside the viewport or in footers), you can manually trigger prefetching using the useRouter hook. This is useful for predictive prefetching based on user behavior—for example, prefetching a user's most common destinations after login, or prefetching based on analytics data. The router.prefetch() method accepts a route path and optionally an onInvalidate callback to refresh stale data . You can also create custom prefetching strategies like hover-only prefetching to balance performance and resource usage [citation:6].
SWR automatically caches data and revalidates in the background, so navigating to a previously visited page shows cached data instantly while fetching updates [citation:3][citation:8].
The stale-while-revalidate pattern means users see stale data immediately while fresh data loads, eliminating loading spinners on repeat visits [citation:1].
React Query provides similar capabilities with prefetchQuery for imperatively loading data before navigation, and query clients that persist across routes.
Combined with Next.js Link prefetching, data libraries ensure both route code and data are available by the time the user navigates, making transitions feel instantaneous [citation:7].
Next.js maintains an intelligent prefetching queue to avoid overwhelming the network or browser. The scheduler prefetches in this order: links currently in the viewport first, then links showing user intent (hover or touch), with newer links replacing older ones in the queue . Links that scroll off-screen are discarded from the queue entirely. This ensures that prefetching resources are focused on the most likely next navigations. Additionally, Next.js stores prefetched React Server Component payloads in an in-memory cache keyed by route segments, reusing parent layouts when navigating between sibling routes to reduce network traffic [citation:6].
Always add loading.tsx files for dynamic routes to enable partial prefetching and immediate visual feedback [citation:9].
Use generateStaticParams for dynamic segments that can be prerendered, allowing them to be treated as static routes for full prefetching [citation:9].
Consider hover-only prefetching for pages with many links (e.g., infinite scroll) to reduce resource usage [citation:6].
Implement useLinkStatus to show immediate feedback on slow networks where prefetching may not complete before navigation [citation:9].
Use the @next/bundle-analyzer to reduce JavaScript bundle size, speeding up hydration and allowing prefetching to start earlier [citation:9].