Understanding the New Rendering Model
Traditionally, React applications relied heavily on client-side rendering (CSR) or server-side rendering (SSR). With React 19 and Next.js 16, we now have a hybrid model:
- Server Components (RSC) → Rendered on the server
- Client Components → Hydrated and interactive in the browser
- Streaming UI → Sent progressively to the client
This model allows you to reduce JavaScript bundle size while improving performance.
Server vs Client Components
By default, components in Next.js 16 are Server Components.
export default async function Page() {
const data = await fetchData();
return <div>{data.title}</div>;
}To make a component interactive:
'use client';The key idea is simple: render as much as possible on the server, and hydrate only what's necessary.
#1 Rendering Deep Dive: What Actually Happens
When a request hits your Next.js app:
- The server renders Server Components
- React generates a special payload (RSC payload)
- HTML is streamed to the browser
- Client Components are hydrated progressively
This is called progressive rendering with streaming.
Why Streaming Matters
Without streaming: The user waits for the full page to load.
With streaming: The user sees content immediately while the rest loads.
Example using Suspense:
import { Suspense } from "react";
export default function Page() {
return (
<Suspense fallback={<Loading />}>
<ProductList />
</Suspense>
);
}This allows parts of your UI to load independently.
- Faster perceived performance
- Better Core Web Vitals (especially LCP)
#2 Caching in Next.js 16: Smarter Than You Think
Caching is one of the most misunderstood parts of Next.js. In Next.js 16, fetch is automatically cached by default in Server Components.
Default Behavior
// This request is cached and deduplicated automatically
await fetch('/api/data');Controlling Cache Behavior
You can explicitly define caching strategies:
Static Data (Cache Forever)
await fetch('/api/data', {
cache: 'force-cache',
});Dynamic Data (No Cache)
await fetch('/api/data', {
cache: 'no-store',
});Revalidation (ISR-style)
await fetch('/api/data', {
next: { revalidate: 60 },
});This means: data is cached and re-fetched every 60 seconds.
Common Caching Mistakes
- Overusing no-store → kills performance
- Forgetting revalidation → stale data
- Mixing client fetching unnecessarily
Rule of thumb: fetch on the server first, cache by default, and opt out only when needed.
- Reduced server load
- Faster responses
- Better scalability
#3 Hydration Explained (And Why It Breaks)
Hydration is the process where React attaches event listeners to server-rendered HTML. In React 19, hydration is more efficient—but still fragile if misused.
How Hydration Works
- Server sends HTML
- Browser renders static content
- React attaches interactivity (hydration)
Problems happen when: Server HTML ≠ Client HTML
Common Hydration Issues
1. Non-Deterministic Values
<p>{Math.random()}</p>This will break hydration because the value differs between server and client.
2. Using Browser APIs on the Server
window.innerWidthThis crashes because window doesn't exist on the server.
Best Practices for Hydration
- Keep Server Components pure
- Move dynamic logic to Client Components
- Avoid time-based or random values in server render
Example fix:
'use client';
import { useEffect, useState } from 'react';
export default function Time() {
const [time, setTime] = useState('');
useEffect(() => {
setTime(new Date().toLocaleTimeString());
}, []);
return <p>{time}</p>;
}- Stable hydration
- Fewer runtime errors
Key Takeaways
- 1Use Server Components by default — fetch data on the server, reduce client-side JavaScript
- 2Leverage Streaming — break UI into smaller chunks, use Suspense boundaries
- 3Cache aggressively — use default caching, add revalidation where needed
- 4Be careful with hydration — ensure consistent output, isolate client-only logic
Final Thoughts
React 19 and Next.js 16 introduce a fundamentally new way of thinking about frontend architecture.
Instead of asking "Should this be SSR or CSR?" — you now ask: "What should run on the server vs the client?"
Understanding rendering, caching, and hydration is the key to unlocking better performance, lower infrastructure costs, and cleaner, more scalable codebases.
- Rendering: Server-first with streaming
- Caching: Built-in and powerful—use it wisely
- Hydration: Fast but sensitive—keep it deterministic