A technical exploration of React Server Component execution boundaries, serialization protocols, and runtime memory optimization.
Modern web application architecture has transitioned through three major rendering paradigms:
In the Next.js App Router, components are Server Components by default. A component only becomes a Client Component when declared with the 'use client' directive at the top of the file.
| Characteristic | React Server Component (RSC) | Client Component ('use client') |
|---|---|---|
| Execution Environment | Server only (Build time or Request time) | Server (prerender) + Client (interactive) |
| Shipped to Browser Bundle | 0 KB JavaScript | Component code + dependencies |
| Direct Backend Access | Yes (Database, Filesystem, Secrets) | No (Must call API routes / Server Actions) |
| React Hooks Available | None (No useState, useEffect) | Full (useState, useEffect, useContext) |
| Browser Events | None (No onClick, onChange) | Supported (onClick, onKeyDown, etc.) |
When a user navigates between routes, Next.js does not fetch HTML strings; it streams a React Server Component (RSC) Payload.
The RSC payload is a compact binary/JSON stream containing:
Props passed from a Server Component to a Client Component must be JSON-serializable:
string, number, boolean, null), plain objects, and arrays are valid.// Server Component (src/app/projects/page.tsx)
import { createClient } from '@/lib/supabase/server'
import ProjectListClient from './project-list-client'
export default async function ProjectsPage() {
const supabase = await createClient()
const { data: projects } = await supabase.from('projects').select('*')
// Data serialized cleanly as JSON array across the RSC boundary
return <ProjectListClient initialProjects={projects ?? []} />
}Streaming SSR allows Next.js to flush static layout elements to the browser immediately while asynchronous data queries are still executing on the server.
import { Suspense } from 'react'
import Header from '@/components/header'
import SlowAnalyticsWidget from '@/components/slow-widget'
import SkeletonLoader from '@/components/skeleton-loader'
export default function DashboardPage() {
return (
<div className="space-y-8">
{/* Flushed to browser immediately */}
<Header title="Analytics Dashboard" />
{/* Renders skeleton instantly; streams widget HTML as soon as query completes */}
<Suspense fallback={<SkeletonLoader />}>
<SlowAnalyticsWidget />
</Suspense>
</div>
)
}By wrapping slow database operations in <Suspense>, the browser's Time to First Byte (TTFB) and First Contentful Paint (FCP) remain sub-second regardless of backend API latency.
For content that changes infrequently (such as engineering case studies or technical blogs), generating pages dynamically on every request wastes server CPU and increases latency.
Next.js 16 provides Incremental Static Regeneration (ISR) via route-level exports:
// src/app/blog/[slug]/page.tsx
import { Metadata } from 'next'
import { notFound } from 'next/navigation'
// Pre-render pages as static HTML at build time, and revalidate in background once per hour
export const revalidate = 3600;
export async function generateStaticParams() {
const posts = await getPublishedPostSlugs()
return posts.map(post => ({ slug: post.slug }))
}
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPostBySlug(slug)
if (!post) notFound()
return <article>{/* Article content */}</article>
}With ISR:
'use client' at Root Levels: Placing 'use client' at the top of page layouts converts the entire subtree into a client bundle, negating the zero-bundle advantage of Server Components. Fix: Push 'use client' down to the smallest interactive leaf nodes (buttons, dropdowns, modal dialogs).Promise.all(): const [userData, projectsData, statsData] = await Promise.all([
getUserProfile(),
getUserProjects(),
getPlatformStats()
])window.addEventListener in useEffect() return callbacks causes memory leaks and duplicate handler execution.revalidate = 3600).generateStaticParams() for pre-rendering known dynamic paths.AI-powered resume optimization platform with spatial ATS parsing, zero-duplicate action verb rewriting, and ATS-safe PDF generation.