TechFeedTechFeed
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

관련 에러

관련 가이드

React 상태 관리 비교 2026 — Zustand vs Jotai vs Redux Toolkit vs ValtioReact Compiler 1.0 실전 마이그레이션 가이드 — useMemo·useCallback 없는 React 개발Clerk vs Auth0 vs NextAuth.js 2026 — SaaS 인증 서비스 완전 비교Vercel AI SDK 6 완전 가이드 — 에이전트 1급 추상화, MCP 풀 지원, DevTools