R
Rishtaara
Next.js: Zero to Full-Stack
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 */); }, []);