Next.js 프로젝트에서 외부 scripts로 인해 발생하는 Sentry Hydration 에러 문제를 해결하는 방법을 알아봅니다.
최근 Next.js 프로젝트에서 애드센스를 추가한 뒤, Sentry에서 Hydration 관련 에러가 급격히 늘어나는 문제를 겪었습니다. 원인은 비교적 단순합니다. 외부 스크립트가 “하이드레이션이 끝나기 전/직후” DOM을 바꿔버리면 서버에서 만든 HTML과 클라이언트가 초기 렌더링으로 기대하는 HTML이 달라질 수 있습니다.
이번 글에서는 “왜 이런 일이 생기는지”를 짚고, Next.js의 next/script로 로딩 타이밍을 조절해 해결한 방법을 공유합니다.
Hydration 에러(또는 hydration mismatch)는 서버에서 렌더링된 HTML과 클라이언트에서 렌더링된 결과가 일치하지 않을 때 발생합니다.
Next.js처럼 SSR을 사용하는 프레임워크는,
이 과정에서 서버 HTML과 클라이언트가 렌더링한 결과가 다르면 React가 경고/에러를 내고, Sentry 같은 도구가 이를 이슈로 수집할 수 있습니다.
참고: hydration mismatch는 실제 사용자에게 치명적인 장애가 아닐 때도 많지만, 에러 추적 도구에는 ‘에러’로 기록될 수 있어 운영 관점에서 신경이 쓰입니다.
Hydration 에러는 기본적으로 “SSR 결과와 CSR 결과가 달라짐”에서 시작합니다.
애드센스(특히 자동 광고) 같은 외부 스크립트는 브라우저에서 로딩되면서 다음을 할 수 있습니다.
Hydration 에러 같은 경우 실제 운영 중에서 큰 문제로 이어지지 않을 수도 있고, 사용자 경험에 크게 영향이 없을 수도 있습니다. 다만 Sentry에서는 이를 “렌더링 불일치(잠재적 버그)”로 간주해 이슈로 잡아낼 수 있습니다.

Sentry에서 확인한 Hydration 에러
다음 영상은 Sentry에서 제공해주는 서버와 클라이언트 렌더링 비교 화면입니다.
영상을 보면 서버와 클라이언트의 렌더링 결과가 다르다는 것을 알 수 있습니다. 비어 있는 부분은 애드센스 자동 광고가 들어갈 영역이거나, 로딩 타이밍에 따라 순간적으로 노출되지 않아 생기는 차이입니다.
즉, 애드센스가 로드되면서 DOM이 바뀌고 → 그 시점이 hydration 근처면 → mismatch가 발생할 수 있습니다.
실제로 제 사이트에 직접 접속해보면 애드센스 광고가 로드되면서 레이아웃이 변경되는 것을 볼 수 있습니다.
순간적으로 DOM이 변경되면서 레이아웃이 “흔들리는” 현상이 보였고, 이는 광고 로딩으로 인한 전형적인 증상이었습니다.
운영 이슈를 줄이려면 “진짜 애드센스 때문인지” 확인이 중요합니다.
제가 선택한 해결책은 간단합니다.
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 관련 이슈가 발생하지 않았습니다(해당 케이스 기준).
beforeInteractive
afterInteractive (기본값)
lazyOnload
Hydration 이슈가 해결돼도, 광고 로딩 시 레이아웃이 흔들리면 UX가 아쉬울 수 있습니다. 가능하다면 광고 영역에 대해 아래도 같이 고려해보면 좋습니다.
광고가 들어갈 컨테이너에 **최소 높이(min-height)**를 지정해서 공간을 미리 확보.
광고 영역을 SSR 단계에서 “자리만” 만들어두고, 실제 로딩은 클라이언트에서 진행.
자동 광고보다는 위치/크기를 통제 가능한 방식이 CLS 면에서 유리한 경우가 있습니다.
애드센스 같은 외부 스크립트는 로딩 과정에서 DOM을 변경할 수 있고, 그 타이밍이 Next.js의 hydration과 겹치면 Sentry에서 hydration mismatch가 에러로 잡힐 수 있습니다.
저는 next/script의 strategy="lazyOnload"로 스크립트 로딩 시점을 hydration 이후로 미루는 방식으로 문제를 해결했습니다.
추가로, 광고 로딩으로 인한 레이아웃 흔들림(CLS)까지 줄이려면 광고 영역의 공간을 미리 확보하는 것도 함께 적용하면 효과가 좋습니다.