Topic 39 of 47
Static Site Generation (SSG) & Server-Side Rendering (SSR) Modes
Overview
Next.js automatically chooses the rendering strategy for each route. SSG renders HTML once at build time (fastest, cacheable on CDN). SSR renders HTML on the server dynamically for every request (always up-to-date, slower).
Syntax
tsx
// STATIC RENDERING (SSG - Default)
// If a route has no dynamic functions (like cookies, headers, searchParams)
// or dynamic data fetching, Next.js statically generates it at build time.
export default async function AboutPage() {
// Fetching with 'force-cache' (the default) keeps the route static
const data = await fetch('https://api.example.com/about').then(r => r.json());
return <main>{data.content}</main>;
}
// DYNAMIC RENDERING (SSR)
// Using dynamic functions opts the route into SSR automatically.
import { cookies } from 'next/headers';
export default async function Dashboard() {
const cookieStore = cookies(); // Dynamic function opts-in to SSR!
const theme = cookieStore.get('theme');
// Using cache: 'no-store' also opts the route into SSR
const user = await fetch('https://api.example.com/me', {
cache: 'no-store'
}).then(r => r.json());
return <div>Welcome {user.name} ({theme?.value})</div>;
}Common Pitfalls
- Be careful using `cookies()`, `headers()`, or `searchParams` on a page you intended to be static. They implicitly convert the route to Dynamic SSR.
- The terms 'SSG' and 'SSR' are from the Pages Router. In the App Router, they are referred to as 'Static Rendering' and 'Dynamic Rendering'.
Real-World Example
Explicitly configuring a route to be Static or Dynamic via Route Segment Configs:
example
tsx
// app/dashboard/page.tsx
// Force the page to always be dynamically rendered (SSR)
export const dynamic = 'force-dynamic';
export default async function Dashboard() {
const data = await db.getLatestData();
return <div>{data.latestUpdate}</div>;
}
// ----------------------------------------
// app/blog/page.tsx
// Force the page to be static (SSG), throwing errors if dynamic functions are used
export const dynamic = 'error';
export default async function BlogIndex() {
const posts = await db.getPosts();
return <BlogList posts={posts} />;
}