Next.js - Pre-Rendering
Next.js - Data Fetching and Rendering Strategies
Section titled “Next.js - Data Fetching and Rendering Strategies”A core feature of Next.js is its ability to pre-render pages, meaning it generates the HTML for each page in advance, rather than having it all done by client-side JavaScript. Pre-rendering leads to better performance and SEO.
Next.js supports different rendering strategies, often combined with data fetching:
1. Static Site Generation (SSG)
Section titled “1. Static Site Generation (SSG)”The HTML is generated at build time. This pre-rendered HTML is then served directly from a CDN on each request, making it incredibly fast. Ideal for pages where the content doesn’t change frequently per user request (e.g., marketing pages, blog posts, documentation, e-commerce product listings).
-
Without Data: If a page doesn’t need external data, it’s automatically statically generated by default.
-
With Data (Pages Router): Use the
getStaticPropsasync function within your page file. This function runs at build time, fetches data, and passes it as props to your page component. The page is then pre-rendered with this data. -
With Data (App Router): Data fetching typically happens directly within Server Components using
async/await. By default, Next.js aggressively caches fetched data, effectively resulting in static rendering. You can control caching behavior with options like{ cache: 'no-store' }or{ next: { revalidate: seconds } }. -
Incremental Static Regeneration (ISR): An extension of SSG. Allows you to update static pages after build time without needing a full rebuild. In
getStaticProps(Pages Router) orfetchoptions (App Router), you can specify arevalidatetime. After this period, the next request will trigger a regeneration of the page in the background.
2. Server-Side Rendering (SSR)
Section titled “2. Server-Side Rendering (SSR)”The HTML for the page is generated on the server for each request. This is useful when the page content needs to be fresh and potentially personalized for every request (e.g., dashboards with user-specific data, pages relying on frequently updated data).
-
Pages Router: Use the
getServerSidePropsasync function. This runs on every request, fetches data, and passes it as props to the page component before rendering the HTML. -
App Router: Use dynamic functions (like
cookies()orheaders()fromnext/headers) or configure data fetching withcache: 'no-store'orrevalidate: 0within Server Components. This opts the route segment into dynamic rendering.
3. Client-Side Rendering (CSR)
Section titled “3. Client-Side Rendering (CSR)”While Next.js emphasizes server-side pre-rendering, you can still fetch data on the client-side within specific components, typically using React’s useEffect hook and a data fetching library (like fetch, axios, or SWR). This is often used for parts of a page that can load after the initial render (e.g., user-specific content on a cached page).
In the App Router, components that use hooks like useState or useEffect must be marked as Client Components using the 'use client' directive at the top of the file.
Example (Pages Router)
Section titled “Example (Pages Router)”Let’s illustrate SSG (getStaticProps) and SSR (getServerSideProps) using the Pages Router.
Page using SSR (getServerSideProps): pages/dashboard.js
import Head from 'next/head';
function DashboardPage({ time }) { return ( <> <Head><title>Dashboard (SSR)</title></Head> <h1>Dashboard</h1> <p>This page was rendered on the server at: {new Date(time).toLocaleTimeString()}</p> <p>(Refresh the page to see the time update on each request)</p> </> );}
// This function runs on every requestexport async function getServerSideProps(context) { console.log('getServerSideProps executed for /dashboard'); // Example: Fetch user-specific data or real-time info // In this simple case, we just get the current time return { props: { time: Date.now() }, // will be passed to the page component as props };}
export default DashboardPage;Page using SSG (getStaticProps): pages/about.js
import Head from 'next/head';
function AboutPage({ buildTime, repoInfo }) { return ( <> <Head><title>About Us (SSG)</title></Head> <h1>About Us</h1> <p>This page was statically generated at build time.</p> <p>Build timestamp: {new Date(buildTime).toLocaleString()}</p> {repoInfo && ( <div> <h2>Next.js Repo Info (Fetched at Build Time)</h2> <p>Stars: {repoInfo.stargazers_count}</p> <p>Open Issues: {repoInfo.open_issues_count}</p> </div> )} </> );}
// This function runs once at build time (in production)export async function getStaticProps() { console.log('getStaticProps executed for /about'); // Example: Fetch data needed for the page const res = await fetch('https://api.github.com/repos/vercel/next.js'); const repoInfo = await res.json();
return { props: { buildTime: Date.now(), repoInfo: { stargazers_count: repoInfo.stargazers_count || 'N/A', open_issues_count: repoInfo.open_issues_count || 'N/A', } }, // Optional: Add revalidate for Incremental Static Regeneration (ISR) // revalidate: 60, // Regenerate page at most once every 60 seconds };}
export default AboutPage;Running and Verifying
Section titled “Running and Verifying”-
Run
npm run buildthennpm run startfor a production build, or justnpm run devfor development. -
Navigate to
/dashboard. Refresh the page multiple times. You’ll see the timestamp update on each refresh, indicating SSR. In development (npm run dev),getServerSidePropsruns on every request. In production, it also runs on every request. -
Navigate to
/about. Refresh the page. The ‘Build timestamp’ and repo info will remain the same (unless ISR is enabled and the revalidation period has passed), indicating the page was generated statically. In development,getStaticPropsruns on each request for easier development, but in production (npm run build), it runs only once at build time (or during revalidation for ISR).
Choosing the right rendering strategy is crucial for performance and user experience. Use SSG/ISR whenever possible, and fall back to SSR or CSR only when necessary.