Static and Dynamic Rendering (SSG & SSR)
Static (SSG): HTML is ready at build time (or after revalidation). Fast CDN delivery. Great for docs, marketing, course lists that change slowly.
Static vs dynamic — when is HTML built?
Static (SSG): HTML is ready at build time (or after revalidation). Fast CDN delivery. Great for docs, marketing, course lists that change slowly.
Dynamic (SSR): HTML is built per request. Great for personalized dashboards, carts, anything that must be fresh or user-specific.
Real-life example: Static is a printed menu at a food stall — same for everyone, updated occasionally. Dynamic is a kitchen order ticket printed when you order — unique each time.
force-dynamic and revalidate
You can hint Next.js how a route should behave. Segment config and fetch options work together.
- dynamic = 'force-static' — try to stay static
- dynamic = 'force-dynamic' — render on every request
- revalidate = number — time-based refresh for static pages
- Using cookies() or headers() often forces dynamic rendering
// app/blog/page.tsx
export const revalidate = 60; // regenerate at most every 60 seconds
export default async function BlogPage() {
const posts = await fetch("https://api.example.com/posts", {
next: { revalidate: 60 },
}).then((r) => r.json());
return (
<ul>
{posts.map((p: { id: string; title: string }) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}// app/account/page.tsx
export const dynamic = "force-dynamic";
export default async function AccountPage() {
// cookies(), headers(), or no-store fetch also opt into dynamic
const res = await fetch("https://api.example.com/me", { cache: "no-store" });
const user = await res.json();
return <h1>Hello, {user.name}</h1>;
}When to use each
Default to static or revalidated when content is shared. Go dynamic when correctness matters more than cache hits.
- Static / revalidate — blog, docs, product catalog, marketing
- Dynamic — auth dashboards, checkout, admin panels, live scores
- Mix them — static shell + dynamic islands via Suspense (next lesson)