Next.js
Beginner
1 min read
Static Site Generation with generateStaticParams
Example
// app/blog/[slug]/page.tsx — Static generation with ISR
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
interface Post {
slug: string;
title: string;
content: string;
publishedAt: string;
}
// Tell Next.js which slugs to pre-render at build time
export async function generateStaticParams() {
const res = await fetch('https://api.example.com/posts?fields=slug');
const posts: Pick<Post, 'slug'>[] = await res.json();
return posts.map((post) => ({ slug: post.slug }));
}
// Revalidate every hour (ISR)
export const revalidate = 3600;
// Allow on-demand generation for slugs not in generateStaticParams
export const dynamicParams = true;
async function getPost(slug: string): Promise<Post | null> {
const res = await fetch(`https://api.example.com/posts/${slug}`, {
next: { revalidate: 3600, tags: [`post-${slug}`] },
});
if (!res.ok) return null;
return res.json();
}
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
const post = await getPost(params.slug);
return { title: post?.title ?? 'Post not found' };
}
export default async function BlogPostPage({
params,
}: {
params: { slug: string };
}) {
const post = await getPost(params.slug);
if (!post) notFound();
return (
<article>
<h1>{post.title}</h1>
<time>{post.publishedAt}</time>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}