MediumStabilityAuto-fixable

Hydration Mismatch in SSR Component

A React component renders different markup on the server than on the client, typically because it reads time, randomness, or browser APIs during initial render.

Typical error

Hydration failed because the initial UI does not match what was rendered on the server

What this is

Next.js renders your page HTML on the server, then hydrates (attaches event handlers) on the client. If the first client render produces different markup, React logs a hydration error. The page may flash the server HTML and then re-render from scratch, destroying Core Web Vitals.

Common causes:

  • Date.now(), new Date(), or Math.random() used during render
  • Reading localStorage, sessionStorage, window, or navigator at render time
  • Third-party scripts injecting markup before React hydrates
  • Conditional rendering based on typeof window !== 'undefined'

Why AI tools ship this

AI-generated components often reach for Date.now() for keys, timestamps, or "random id" patterns without realizing those change between server and client.

How to detect

Watch the browser console on first load. "Hydration failed" and "Text content does not match server-rendered HTML" are the canonical messages.

For static detection, grep:

grep -rE "(Math.random|Date.now|new Date\(\))" --include="*.tsx" app components

Any occurrence in a non-event-handler position is suspect.

How to fix

Wrap anything that must only run on the client:

'use client'
import { useEffect, useState } from 'react'
 
export function ClientOnly({ children }: { children: React.ReactNode }) {
  const [mounted, setMounted] = useState(false)
  useEffect(() => setMounted(true), [])
  if (!mounted) return null
  return <>{children}</>
}

Or move the non-deterministic value out of render into a useEffect:

const [now, setNow] = useState<number | null>(null)
useEffect(() => setNow(Date.now()), [])

For ids, use React's useId() hook instead of random values.

Commonly affected tools

Glossary

Is your app affected?

FinishKit checks for this finding and 50+ more across 8 dimensions of production readiness. Free during beta.

Scan your app