Skip to content

Rendering Modes

Server-Side Rendering, Static Site Generation, and Incremental Static Regeneration

NestForge Web supports multiple rendering strategies for optimal performance and user experience.

SSR renders pages on the server for each request. Best for dynamic content.

src/app/dashboard/page.tsx
export const dynamic = "force-dynamic";
export default async function DashboardPage() {
const user = await getCurrentUser();
const data = await fetchLatestData();
return (
<Dashboard user={user} data={data} />
);
}
  • User-specific content (dashboards, profiles)
  • Frequently changing data
  • Real-time information
  • SEO-critical dynamic pages

SSG renders pages at build time. Best for content that rarely changes.

src/app/about/page.tsx
export default function AboutPage() {
return (
<main>
<h1>About Us</h1>
<p>Static content rendered at build time</p>
</main>
);
}
src/app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPostBySlug(params.slug);
return <Article post={post} />;
}
  • Marketing pages (landing, about, pricing)
  • Documentation
  • Blog posts
  • Content that doesn’t change often

ISR combines SSG and SSR - pages are statically generated but can be regenerated in the background.

src/app/blog/page.tsx
export const revalidate = 60; // Revalidate every 60 seconds
export default async function BlogIndex() {
const posts = await fetchPosts();
return (
<main>
<h1>Blog</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
</li>
))}
</ul>
</main>
);
}
src/app/api/revalidate/route.ts
export async function POST(request: Request) {
const body = await request.json();
const secret = request.headers.get("x-revalidate-secret");
if (secret !== process.env.REVALIDATE_SECRET) {
return Response.json({ error: "Invalid secret" }, { status: 401 });
}
await revalidatePath(`/blog/${body.slug}`);
return Response.json({ revalidated: true });
}
  • Content that updates periodically
  • E-commerce product pages
  • News or blog listings
  • Pages with mix of static/dynamic content
ModeWhen RenderedPerformanceUse Case
SSREach requestSlower (fresh data)Dynamic user content
SSGBuild timeFastest (static)Static marketing/docs
ISRBuild + backgroundFast + freshDynamic + performant
// Opt out of static rendering (SSR)
export const dynamic = "force-dynamic";
// Use PPR (Partial Prerendering) - experimental
export const dynamic = "force-static";
// Set runtime
export const runtime = "edge"; // or "nodejs"
// Set revalidation for ISR
export const revalidate = 3600; // 1 hour
// Set fetch cache behavior
export const fetchCache = "force-no-store";

Deploy to edge locations for lowest latency:

export const runtime = "edge";
export default async function EdgePage() {
const data = await fetch("https://api.example.com/data", {
next: { revalidate: 60 },
});
return <Page data={data} />;
}
RuntimeLatencyCapabilitiesCold Start
Edge~0ms (global)Limited APIs~0ms
Node.jsRegion-basedFull Node APIs~50ms