Hydration Mismatch (SSR)
The server-rendered HTML doesn't match what the client-side JavaScript expected to render.
Explanation
Hydration mismatch occurs in server-side rendering (SSR) frameworks like Next.js, Nuxt, or Inertia.js when the HTML generated on the server differs from what the client-side JavaScript would generate. This causes the client to re-render the entire component tree, negating SSR performance benefits. Common causes include using browser-only APIs on the server (window, document), rendering random/dynamic content that differs between server and client, using Date.now() or Math.random(), and conditional rendering based on client-side state.
Common Causes
- Using browser-only APIs on server
- Dynamic content differing between server/client
- Date/time rendering differences
- Random values without fixed seed
- Conditional rendering based on client state
Solution
Ensure server and client render identical content by avoiding browser-only APIs during initial render. Use useEffect() or componentDidMount() for browser-specific code. Seed random generators with the same value on server and client. Wrap browser-only components with dynamic imports and ssr: false. Use suppressHydrationWarning for intentional differences (e.g., timestamps). In Next.js, use next/dynamic with ssr: false for client-only components. In Nuxt, use <client-only> wrapper component.
Code Example
// This causes hydration mismatch
function Clock() {
return <div>{new Date().toLocaleString()}</div>; // different on server!
}
// Fix: render empty on server, update on client
function Clock() {
const [time, setTime] = useState('');
useEffect(() => {
setTime(new Date().toLocaleString());
}, []);
return <div>{time}</div>;
}
// Next.js: dynamic import with no SSR
import dynamic from 'next/dynamic';
const InteractiveWidget = dynamic(
() => import('./InteractiveWidget'),
{ ssr: false }
);
// Nuxt: client-only component
<template>
<client-only>
<InteractiveWidget />
</client-only>
</template>
// Inertia.js: use only property for client rendering
<div>
{{ \Carbon\Carbon::now()->format('Y-m-d') }}
</div>
Error Information
Language
javascript
Difficulty
Intermediate
Views
12
Related Errors
JavaScript
RangeError: Maximum Call Stack Size Exceeded
The function calls itself recursively too many times, exceeding the stack size limit.
Frontend
WebSocket Connection Failed
The WebSocket connection could not be established or was closed unexpectedly.
Frontend
ChunkLoadError
A dynamically imported JavaScript chunk failed to load from the server.
Frontend
ResizeObserver Loop Limit Exceeded
A ResizeObserver callback triggered layout changes that caused another resize, creating an infinite loop.