Next.js런타임
Next.js Hydration 실패 — text content does not match
Hydration failed because the server rendered HTML didn't match the client
한 줄 해결: 서버에서 렌더한 HTML 과 클라이언트 첫 렌더 결과가 달라 발생하며, 렌더 중 브라우저 전용 값(시간·랜덤·localStorage)을 쓰지 않는 것이 핵심입니다.
이런 증상일 때
페이지 로드 직후 콘솔에 "Hydration failed" 또는 "Text content does not match server-rendered HTML" 경고가 뜨고, 화면이 깜빡이거나 일부가 다시 그려집니다. App Router·Pages Router 모두에서 발생합니다.
원인
- 렌더 중 new Date()·Math.random()·Date.now() 처럼 매 렌더 달라지는 값 사용
- typeof window 분기나 localStorage/navigator 값을 첫 렌더에 직접 반영
- 잘못된 HTML 중첩(<p> 안에 <div>, <a> 안에 <a> 등)으로 브라우저가 DOM 을 교정
- 확장 프로그램이나 darkmode 스크립트가 hydration 전에 DOM 을 수정
해결 방법
1
클라이언트 전용 값은 useEffect 이후로
시간·랜덤·스토리지 값은 첫 렌더에서 빼고, 마운트 후 useEffect 에서 setState 로 채웁니다. 서버/클라 첫 렌더가 같아집니다.
const [t, setT] = useState(null)
useEffect(() => setT(new Date().toLocaleString()), [])2
suppressHydrationWarning (불가피한 경우)
시간 표시처럼 본질적으로 다를 수밖에 없는 단일 요소엔 이 속성으로 경고를 억제합니다. 남용 금지.
<time suppressHydrationWarning>{t}</time>3
동적 import 로 SSR 끄기
브라우저 API 에 강하게 의존하는 컴포넌트는 ssr:false 로 클라이언트에서만 렌더합니다.
const Chart = dynamic(() => import('./Chart'), { ssr: false })4
HTML 중첩 점검
<p> 안의 블록 요소, <a> 중첩 등 잘못된 마크업을 바로잡습니다. React 19 는 이 경우 더 명확한 에러를 표시합니다.
💡 예방: 렌더 함수는 순수하게 유지하고, 환경 의존 값은 항상 마운트 이후에 주입하세요.
Next.jsReacthydrationSSRuse client