PromptHub
Frontend Intermediate 11 views

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

11

Related Errors