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

StrategyNext.jsWhen
Static (SSG)Default for routes without request dataMarketing, docs, blog posts
Static with paramsgenerateStaticParamsKnown set of slugs
Dynamic (SSR)Using cookies(), headers(), searchParams, uncached dataPersonalized pages
Partial prerenderingcacheComponents: true + <Suspense>Static shell, dynamic holes
Static exportoutput: '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

Next.js
// 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.js
// next.config.ts — full static siteconst nextConfig: NextConfig = { output: "export" };
Angular
// 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).
  • getPrerenderParams runs in an injection context, so inject() works inside it.
  • fallback in Angular ≈ dynamicParams in Next.js: what happens for params not prerendered.

Quick reference

Next.jsAngular
Static by defaultRenderMode.Prerender
Dynamic (request data)RenderMode.Server
generateStaticParamsgetPrerenderParams
dynamicParamsfallback (Server, Client, None)
output: 'export'All routes Prerender/Client, deploy browser/