Lesson 24 of 42Article15 min
generateStaticParams & Data Fetching Methods
For dynamic routes like app/blog/[slug]/page.tsx, generateStaticParams tells Next.js which slugs to build as static HTML at build time.
generateStaticParams — prebuild known paths
For dynamic routes like app/blog/[slug]/page.tsx, generateStaticParams tells Next.js which slugs to build as static HTML at build time.
Real-life example: It is printing popular metro maps the night before — tomorrow riders get them instantly; rare stations can still be printed on demand.
app/blog/[slug]/page.tsx
type Props = { params: Promise<{ slug: string }> };
export async function generateStaticParams() {
const posts = await fetch("https://api.example.com/posts").then((r) =>
r.json()
);
return posts.map((post: { slug: string }) => ({
slug: post.slug,
}));
}
export default async function BlogPostPage({ params }: Props) {
const { slug } = await params;
const post = await fetch(`https://api.example.com/posts/${slug}`, {
next: { revalidate: 3600 },
}).then((r) => r.json());
return (
<article>
<h1>{post.title}</h1>
<div>{post.body}</div>
</article>
);
}Comparing SSG, SSR, and client fetch
Same UI, different places and times for the network call. Pick the leftmost option that still meets your freshness and privacy needs.
- SSG / generateStaticParams — build-time HTML, CDN fast, shared content
- SSR / no-store / force-dynamic — per-request HTML, personalized or fresh
- Client fetch — after JS loads; use for polls, search-as-you-type, browser-only APIs
For public blog posts, generateStaticParams + revalidate is usually enough. Save client fetching for interactive filters that change every keystroke.
Mental model cheat sheet
// 1) Static path list at build
export async function generateStaticParams() { /* ... */ }
// 2) Server fetch with revalidate (shared, slightly stale OK)
await fetch(url, { next: { revalidate: 60 } });
// 3) Server fetch always fresh
await fetch(url, { cache: "no-store" });
// 4) Client — only when server cannot do the job
"use client";
useEffect(() => { fetch("/api/...").then(/* setState */); }, []);