Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Static and dynamic rendering

Next.js can prepare a page's HTML once at build time — that is static rendering. Or it can render the page again for every visitor — that is dynamic rendering. A static page is served instantly, a dynamic one always shows current data. Next.js chooses the mode itself by looking at the page code.

How Next.js decides

A page becomes dynamic if it uses something known only at request time:

What the page usesMode
Only its own data and fetchStatic
cookies() or headers()Dynamic
The searchParams propDynamic
export const dynamic = 'force-dynamic'Dynamic
A dynamic segment without generateStaticParamsDynamic

How to see the mode

Build the project:

npm run build

At the end the terminal shows a table of routes. The ○ symbol means a static page, ƒ a dynamic one, ● static pages built from a list of parameters. Everything in this lesson applies to the regular Next.js 16 model; with Cache Components turned on the rules differ, and they get a separate lesson.

generateStaticParams

The post page app/posts/[slug]/page.tsx is dynamic by default: Next.js does not know the possible slug values in advance. The generateStaticParams function provides that list:

// app/posts/[slug]/page.tsx
import { notFound } from 'next/navigation';
import { getPost, getPosts } from '@/lib/posts';
 
export async function generateStaticParams() {
  const posts = await getPosts();
  return posts.map((post) => ({ slug: post.slug }));
}
 
export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) notFound();
 
  return <h1>{post.title}</h1>;
}

The function returns an array of objects, one per page; the key matches the folder name. After npm run build the table shows ● and the addresses /posts/hello-nextjs and /posts/server-components — their HTML is ready in advance.

New posts after the build

A post added after the build still opens: Next.js renders it on the first request and stores it. If such addresses should give a 404, add to the page file:

// app/posts/[slug]/page.tsx (fragment)
export const dynamicParams = false;

A forced dynamic page

If a page must show fresh database data on every request, say so explicitly:

// app/posts/page.tsx (fragment)
export const dynamic = 'force-dynamic';

Then /posts is no longer built in advance and gets the ƒ symbol in the build table. A softer option is export const revalidate = 60 from the caching lesson.

Common mistake

Reading the list of posts from a database on a page without these settings and wondering why new posts never appear on the server. A page without dynamic functions was built statically, and its HTML does not change. Choose explicitly: revalidate, dynamic = 'force-dynamic' or revalidatePath after the data changes.

Thanks for reading!

Donate to the site — we work hard for you.