Next.js: The React Framework (App Router)Entry 11 of 16
Rendering Strategies: Static, Dynamic, and Export
A route is static (rendered at build time) unless it reads request data or uncached data, which makes it dynamic (rendered per request). generateStaticParams prerenders dynamic routes; output: 'export' produces a plain static site.
Notes
| Strategy | Next.js | When |
|---|---|---|
| Static (SSG) | Default for routes without request data | Marketing, docs, blog posts |
| Static with params | generateStaticParams | Known set of slugs |
| Dynamic (SSR) | Using cookies(), headers(), searchParams, uncached data | Personalized pages |
| Partial prerendering | cacheComponents: true + <Suspense> | Static shell, dynamic holes |
| Static export | output: 'export' | Any static host, no Node server |
With static export, server-only features (request APIs, Server Actions, route handlers other than static GET, revalidate*) aren't available. POR itself could use output: 'export'.
What / Why / When
- What
Choosing build-time vs request-time rendering per route.
- Why
Static pages are cheapest and fastest; dynamic pages are needed for per-user content.
- When
Prerender everything you can; go dynamic only where the content depends on the request.
- Use case
Prerendering every blog post at build time.
Code compare
// app/posts/[slug]/page.tsxexport 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); return <h1>{post.title}</h1>;}// next.config.ts — full static siteconst nextConfig: NextConfig = { output: "export" };// app.routes.server.tsimport { inject } from "@angular/core";import { firstValueFrom } from "rxjs";import { PrerenderFallback, RenderMode, ServerRoute } from "@angular/ssr";import { PostService } from "./posts/post.service";export const serverRoutes: ServerRoute[] = [ { path: "posts/:slug", renderMode: RenderMode.Prerender, async getPrerenderParams() { const posts = await firstValueFrom(inject(PostService).getPosts()); return posts.map((post) => ({ slug: post.slug })); }, fallback: PrerenderFallback.Server, // unknown slugs render on request }, { path: "account/**", renderMode: RenderMode.Server }, { path: "**", renderMode: RenderMode.Prerender },];A fully static Angular site: give every route RenderMode.Prerender (or Client) and deploy the browser/ build output to a static host.
Differences and gotchas
- Next.js infers static vs dynamic from your code; Angular makes you declare it per route. Angular's way is more explicit; Next.js's is easier to accidentally change (one
cookies()call makes a route dynamic). getPrerenderParamsruns in an injection context, soinject()works inside it.fallbackin Angular ≈dynamicParamsin Next.js: what happens for params not prerendered.
Quick reference
| Next.js | Angular |
|---|---|
| Static by default | RenderMode.Prerender |
| Dynamic (request data) | RenderMode.Server |
generateStaticParams | getPrerenderParams |
dynamicParams | fallback (Server, Client, None) |
output: 'export' | All routes Prerender/Client, deploy browser/ |