Modern Web Rendering Decoded: Choosing Between SSR, CSR, SSG, and ISR in Next.js 14
The Evolution of Rendering Strategies
Modern web developers no longer have to choose between a blank Single Page App (CSR) and heavy legacy server templates. Next.js 14 App Router and React Server Components (RSC) introduce granular hybrid rendering paradigms that can be tuned per route.
Understanding when and how to leverage SSR, CSR, SSG, and ISR is essential for balancing server resource consumption, database load, and sub-second page performance.
1. Comparing the Four Core Rendering Models
| Strategy | When Rendered | JavaScript Sent to Client | Best Use Case |
| :--- | :--- | :--- | :--- |
| SSG (Static Site Gen) | Build Time | Zero (for RSC) | Documentation, Marketing, Blogs |
| ISR (Incremental Static) | Background on Demand / Timer | Minimal / Hydrated components | E-commerce catalogs, Portfolio feeds |
| SSR (Server-Side) | Every Request | Hydration payloads | Real-time user dashboards, Live stock tickers |
| CSR (Client-Side) | In Browser Runtime | Full component trees | Interactive canvases, Canvas editors, Games |
2. Deep Dive: Incremental Static Regeneration (ISR)
ISR provides the speed of static HTML with the dynamic freshness of server rendering. Rather than rebuilding the entire static site for every content change, Next.js regenerates pages in the background when requested or via on-demand triggers:
Time-Based Revalidation
// app/blog/page.tsx
import { getBlogPosts } from "@/lib/supabase-queries";
// Revalidate this static page at most every 60 seconds
export const revalidate = 60;
export default async function BlogFeedPage() {
const posts = await getBlogPosts();
return <BlogFeedClient posts={posts} />;
}On-Demand Server Action Cache Invalidation
Whenever an admin updates a blog post or publishes a project, trigger immediate revalidation:
'use server';
import { revalidatePath, revalidateTag } from 'next/cache';
import { createClient } from '@/utils/supabase/server';
export async function publishPostAction(formData: FormData) {
const supabase = createClient();
const slug = formData.get('slug') as string;
await supabase.from('blog_posts').update({ status: 'PUBLISHED' }).eq('slug', slug);
// Invalidate both the post detail and the blog feed instantly
revalidatePath(`/blog/${slug}`);
revalidatePath('/blog');
revalidatePath('/admin/blogs');
return { success: true };
}3. The Golden Rule of Cookieless Server Queries
A common pitfall in Next.js 14 is reading cookies or session headers during public page rendering. Accessing cookies() or headers() inside a Server Component automatically forces the page into Dynamic SSR, disabling SSG and ISR.
To preserve lightning-fast static generation for public pages:
- Use an anonymous, stateless Supabase/API client (
createAnonClient) for public reads. - Use authenticated cookie-based clients only inside authenticated admin layouts, route handlers, or Server Actions.
4. Architectural Summary
- Public Marketing & Content Pages: Default to SSG + ISR with cookieless query helpers.
- Dynamic User Portals & Admin Dashboards: Use SSR with Suspense boundaries for streaming UI.
- Complex In-Browser Tools (Editors, Audio Visualizers): Isolate to CSR leaf components marked with
'use client'.
Discussion (0)
Technical insights, critiques, and feedback
No comments yet. Be the first to start the discussion!