Recode Log

  • tech-blog
  • device
  • features
Copyright © [WebKBS]. All rights reserved.
  • tech-blog
  • device
  • features
  1. Home
  2. issues
  3. Next.js Sentry Hydration 에러 해결

Next.js Sentry Hydration 에러 해결

Next.js 프로젝트에서 외부 scripts로 인해 발생하는 Sentry Hydration 에러 문제를 해결하는 방법을 알아봅니다.

  • next.js 16
2025년 12월 19일

최근 Next.js 프로젝트에서 애드센스를 추가한 뒤, Sentry에서 Hydration 관련 에러가 급격히 늘어나는 문제를 겪었습니다. 원인은 비교적 단순합니다. 외부 스크립트가 “하이드레이션이 끝나기 전/직후” DOM을 바꿔버리면 서버에서 만든 HTML과 클라이언트가 초기 렌더링으로 기대하는 HTML이 달라질 수 있습니다.

이번 글에서는 “왜 이런 일이 생기는지”를 짚고, Next.js의 next/script로 로딩 타이밍을 조절해 해결한 방법을 공유합니다.

Hydration 에러란?

Hydration 에러(또는 hydration mismatch)는 서버에서 렌더링된 HTML과 클라이언트에서 렌더링된 결과가 일치하지 않을 때 발생합니다.

Next.js처럼 SSR을 사용하는 프레임워크는,

  1. 서버에서 초기 HTML을 만들고
  2. 브라우저에서 React가 그 HTML에 이벤트/상태를 연결하며(=Hydration)
  3. “상호작용 가능한 앱”으로 바꿉니다.

이 과정에서 서버 HTML과 클라이언트가 렌더링한 결과가 다르면 React가 경고/에러를 내고, Sentry 같은 도구가 이를 이슈로 수집할 수 있습니다.

참고: hydration mismatch는 실제 사용자에게 치명적인 장애가 아닐 때도 많지만, 에러 추적 도구에는 ‘에러’로 기록될 수 있어 운영 관점에서 신경이 쓰입니다.

문제 원인 분석

Hydration 에러는 기본적으로 “SSR 결과와 CSR 결과가 달라짐”에서 시작합니다.

애드센스(특히 자동 광고) 같은 외부 스크립트는 브라우저에서 로딩되면서 다음을 할 수 있습니다.

  • 광고 영역을 삽입하기 위해 DOM을 추가/변경
  • 레이아웃을 재계산하며 일부 영역의 높이/구조를 변경
  • 초기 렌더 직후 매우 빠르게 변화를 주어 “React가 기대하던 DOM 구조”를 흔들어버림

Hydration 에러 같은 경우 실제 운영 중에서 큰 문제로 이어지지 않을 수도 있고, 사용자 경험에 크게 영향이 없을 수도 있습니다. 다만 Sentry에서는 이를 “렌더링 불일치(잠재적 버그)”로 간주해 이슈로 잡아낼 수 있습니다.

Sentry에서 확인한 Hydration 에러

Sentry에서 확인한 Hydration 에러

다음 영상은 Sentry에서 제공해주는 서버와 클라이언트 렌더링 비교 화면입니다.

Sentry Hydration Error 영상
Sentry Hydration Error 영상

영상을 보면 서버와 클라이언트의 렌더링 결과가 다르다는 것을 알 수 있습니다. 비어 있는 부분은 애드센스 자동 광고가 들어갈 영역이거나, 로딩 타이밍에 따라 순간적으로 노출되지 않아 생기는 차이입니다.

즉, 애드센스가 로드되면서 DOM이 바뀌고 → 그 시점이 hydration 근처면 → mismatch가 발생할 수 있습니다.

실제로 제 사이트에 직접 접속해보면 애드센스 광고가 로드되면서 레이아웃이 변경되는 것을 볼 수 있습니다.

순간적으로 DOM이 변경되면서 레이아웃이 “흔들리는” 현상이 보였고, 이는 광고 로딩으로 인한 전형적인 증상이었습니다.

애드센스 로드로 인한 Hydration 에러 영상
애드센스 로드로 인한 Hydration 에러 영상

재현/확인 체크리스트

운영 이슈를 줄이려면 “진짜 애드센스 때문인지” 확인이 중요합니다.

  • 시크릿 모드에서 재현되는지 확인 (확장 프로그램이 DOM을 바꿔 hydration mismatch를 만드는 경우도 많습니다)
  • 해당 페이지에서 광고 스크립트를 잠시 제거했을 때 Sentry 이슈가 줄어드는지 확인
  • Sentry 이슈 상세에서 “Diff(서버/클라 HTML 차이)”가 광고 영역 근처인지 확인

해결 방법

제가 선택한 해결책은 간단합니다.

  • 애드센스 스크립트의 실행 타이밍을 “hydration 이후”로 최대한 늦춘다
  • Next.js에서 권장하는 방식인 next/script를 사용해 로딩 전략을 명확히 한다

아래처럼 next/script로 애드센스 스크립트를 로드하고, strategy="lazyOnload"로 로딩을 늦췄습니다.

import Script from "next/script";
 
<Script
  async
  src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"
  crossOrigin="anonymous"
  strategy="lazyOnload"
/>;

next/script는 Next.js에서 제공하는 스크립트 로딩 최적화 컴포넌트입니다. 특히 lazyOnload는 페이지가 완전히 로드된 뒤 스크립트를 비동기로 가져오도록 하여, hydration 타이밍과 충돌할 가능성을 낮춰줍니다.

중요한 포인트: “DOM이 절대 바뀌지 않는다”라기보다, React hydration이 끝난 이후에 DOM 변경이 일어나도록 타이밍을 뒤로 미는 것이 핵심입니다.

이렇게 적용한 뒤에는 Sentry에서 더 이상 Hydration 관련 이슈가 발생하지 않았습니다(해당 케이스 기준).

Script 컴포넌트 옵션 정리

  • beforeInteractive

    • Next.js 코드 및 페이지가 로딩되기 전에 스크립트를 로드합니다.
    • 정말 필수이며 초기 렌더 이전에 필요한 스크립트(ex. 일부 A/B 테스트 핵심, 매우 특수한 케이스)에만 권장됩니다.
  • afterInteractive (기본값)

    • 페이지가 로드된 후(인터랙티브해진 후) 스크립트를 로드합니다.
    • 대부분의 일반적인 스크립트에 사용합니다.
  • lazyOnload

    • 페이지가 완전히 로드된 후 스크립트를 비동기적으로 로드합니다.
    • 성능 최적화 및 hydration 충돌 완화에 유리합니다.

레이아웃 흔들림(CLS)까지 줄이는 팁

Hydration 이슈가 해결돼도, 광고 로딩 시 레이아웃이 흔들리면 UX가 아쉬울 수 있습니다. 가능하다면 광고 영역에 대해 아래도 같이 고려해보면 좋습니다.

광고가 들어갈 컨테이너에 **최소 높이(min-height)**를 지정해서 공간을 미리 확보.

광고 영역을 SSR 단계에서 “자리만” 만들어두고, 실제 로딩은 클라이언트에서 진행.

자동 광고보다는 위치/크기를 통제 가능한 방식이 CLS 면에서 유리한 경우가 있습니다.

결론

애드센스 같은 외부 스크립트는 로딩 과정에서 DOM을 변경할 수 있고, 그 타이밍이 Next.js의 hydration과 겹치면 Sentry에서 hydration mismatch가 에러로 잡힐 수 있습니다.

저는 next/script의 strategy="lazyOnload"로 스크립트 로딩 시점을 hydration 이후로 미루는 방식으로 문제를 해결했습니다.

추가로, 광고 로딩으로 인한 레이아웃 흔들림(CLS)까지 줄이려면 광고 영역의 공간을 미리 확보하는 것도 함께 적용하면 효과가 좋습니다.


다음글

prisma와 supabase 사용시 db pull 및 db push 연결 안되는 문제 해결 방법


관련 태그

  • sentry
  • Next.js
  • hydration